Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2018 Netronome Systems, Inc. */
0003 /* This program is free software; you can redistribute it and/or
0004  * modify it under the terms of version 2 of the GNU General Public
0005  * License as published by the Free Software Foundation.
0006  */
0007 #include <errno.h>
0008 #include <fcntl.h>
0009 #include <bpf/libbpf.h>
0010 #include <poll.h>
0011 #include <signal.h>
0012 #include <stdbool.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <time.h>
0017 #include <unistd.h>
0018 #include <linux/bpf.h>
0019 #include <linux/perf_event.h>
0020 #include <sys/ioctl.h>
0021 #include <sys/mman.h>
0022 #include <sys/syscall.h>
0023 
0024 #include <bpf/bpf.h>
0025 
0026 #include "main.h"
0027 
0028 #define MMAP_PAGE_CNT   16
0029 
0030 static volatile bool stop;
0031 
0032 struct event_ring_info {
0033     int fd;
0034     int key;
0035     unsigned int cpu;
0036     void *mem;
0037 };
0038 
0039 struct perf_event_sample {
0040     struct perf_event_header header;
0041     __u64 time;
0042     __u32 size;
0043     unsigned char data[];
0044 };
0045 
0046 struct perf_event_lost {
0047     struct perf_event_header header;
0048     __u64 id;
0049     __u64 lost;
0050 };
0051 
0052 static void int_exit(int signo)
0053 {
0054     fprintf(stderr, "Stopping...\n");
0055     stop = true;
0056 }
0057 
0058 struct event_pipe_ctx {
0059     bool all_cpus;
0060     int cpu;
0061     int idx;
0062 };
0063 
0064 static enum bpf_perf_event_ret
0065 print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
0066 {
0067     struct perf_event_sample *e = container_of(event,
0068                            struct perf_event_sample,
0069                            header);
0070     struct perf_event_lost *lost = container_of(event,
0071                             struct perf_event_lost,
0072                             header);
0073     struct event_pipe_ctx *ctx = private_data;
0074     int idx = ctx->all_cpus ? cpu : ctx->idx;
0075 
0076     if (json_output) {
0077         jsonw_start_object(json_wtr);
0078         jsonw_name(json_wtr, "type");
0079         jsonw_uint(json_wtr, e->header.type);
0080         jsonw_name(json_wtr, "cpu");
0081         jsonw_uint(json_wtr, cpu);
0082         jsonw_name(json_wtr, "index");
0083         jsonw_uint(json_wtr, idx);
0084         if (e->header.type == PERF_RECORD_SAMPLE) {
0085             jsonw_name(json_wtr, "timestamp");
0086             jsonw_uint(json_wtr, e->time);
0087             jsonw_name(json_wtr, "data");
0088             print_data_json(e->data, e->size);
0089         } else if (e->header.type == PERF_RECORD_LOST) {
0090             jsonw_name(json_wtr, "lost");
0091             jsonw_start_object(json_wtr);
0092             jsonw_name(json_wtr, "id");
0093             jsonw_uint(json_wtr, lost->id);
0094             jsonw_name(json_wtr, "count");
0095             jsonw_uint(json_wtr, lost->lost);
0096             jsonw_end_object(json_wtr);
0097         }
0098         jsonw_end_object(json_wtr);
0099     } else {
0100         if (e->header.type == PERF_RECORD_SAMPLE) {
0101             printf("== @%lld.%09lld CPU: %d index: %d =====\n",
0102                    e->time / 1000000000ULL, e->time % 1000000000ULL,
0103                    cpu, idx);
0104             fprint_hex(stdout, e->data, e->size, " ");
0105             printf("\n");
0106         } else if (e->header.type == PERF_RECORD_LOST) {
0107             printf("lost %lld events\n", lost->lost);
0108         } else {
0109             printf("unknown event type=%d size=%d\n",
0110                    e->header.type, e->header.size);
0111         }
0112     }
0113 
0114     return LIBBPF_PERF_EVENT_CONT;
0115 }
0116 
0117 int do_event_pipe(int argc, char **argv)
0118 {
0119     struct perf_event_attr perf_attr = {
0120         .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME,
0121         .type = PERF_TYPE_SOFTWARE,
0122         .config = PERF_COUNT_SW_BPF_OUTPUT,
0123         .sample_period = 1,
0124         .wakeup_events = 1,
0125     };
0126     struct bpf_map_info map_info = {};
0127     LIBBPF_OPTS(perf_buffer_raw_opts, opts);
0128     struct event_pipe_ctx ctx = {
0129         .all_cpus = true,
0130         .cpu = -1,
0131         .idx = -1,
0132     };
0133     struct perf_buffer *pb;
0134     __u32 map_info_len;
0135     int err, map_fd;
0136 
0137     map_info_len = sizeof(map_info);
0138     map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len);
0139     if (map_fd < 0)
0140         return -1;
0141 
0142     if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
0143         p_err("map is not a perf event array");
0144         goto err_close_map;
0145     }
0146 
0147     while (argc) {
0148         if (argc < 2) {
0149             BAD_ARG();
0150             goto err_close_map;
0151         }
0152 
0153         if (is_prefix(*argv, "cpu")) {
0154             char *endptr;
0155 
0156             NEXT_ARG();
0157             ctx.cpu = strtoul(*argv, &endptr, 0);
0158             if (*endptr) {
0159                 p_err("can't parse %s as CPU ID", *argv);
0160                 goto err_close_map;
0161             }
0162 
0163             NEXT_ARG();
0164         } else if (is_prefix(*argv, "index")) {
0165             char *endptr;
0166 
0167             NEXT_ARG();
0168             ctx.idx = strtoul(*argv, &endptr, 0);
0169             if (*endptr) {
0170                 p_err("can't parse %s as index", *argv);
0171                 goto err_close_map;
0172             }
0173 
0174             NEXT_ARG();
0175         } else {
0176             BAD_ARG();
0177             goto err_close_map;
0178         }
0179 
0180         ctx.all_cpus = false;
0181     }
0182 
0183     if (!ctx.all_cpus) {
0184         if (ctx.idx == -1 || ctx.cpu == -1) {
0185             p_err("cpu and index must be specified together");
0186             goto err_close_map;
0187         }
0188     } else {
0189         ctx.cpu = 0;
0190         ctx.idx = 0;
0191     }
0192 
0193     opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
0194     opts.cpus = &ctx.cpu;
0195     opts.map_keys = &ctx.idx;
0196     pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &perf_attr,
0197                   print_bpf_output, &ctx, &opts);
0198     err = libbpf_get_error(pb);
0199     if (err) {
0200         p_err("failed to create perf buffer: %s (%d)",
0201               strerror(err), err);
0202         goto err_close_map;
0203     }
0204 
0205     signal(SIGINT, int_exit);
0206     signal(SIGHUP, int_exit);
0207     signal(SIGTERM, int_exit);
0208 
0209     if (json_output)
0210         jsonw_start_array(json_wtr);
0211 
0212     while (!stop) {
0213         err = perf_buffer__poll(pb, 200);
0214         if (err < 0 && err != -EINTR) {
0215             p_err("perf buffer polling failed: %s (%d)",
0216                   strerror(err), err);
0217             goto err_close_pb;
0218         }
0219     }
0220 
0221     if (json_output)
0222         jsonw_end_array(json_wtr);
0223 
0224     perf_buffer__free(pb);
0225     close(map_fd);
0226 
0227     return 0;
0228 
0229 err_close_pb:
0230     perf_buffer__free(pb);
0231 err_close_map:
0232     close(map_fd);
0233     return -1;
0234 }