Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * sampleip: sample instruction pointer and frequency count in a BPF map.
0004  *
0005  * Copyright 2016 Netflix, Inc.
0006  */
0007 #include <stdio.h>
0008 #include <stdlib.h>
0009 #include <unistd.h>
0010 #include <errno.h>
0011 #include <signal.h>
0012 #include <string.h>
0013 #include <linux/perf_event.h>
0014 #include <linux/ptrace.h>
0015 #include <linux/bpf.h>
0016 #include <bpf/bpf.h>
0017 #include <bpf/libbpf.h>
0018 #include "perf-sys.h"
0019 #include "trace_helpers.h"
0020 
0021 #define DEFAULT_FREQ    99
0022 #define DEFAULT_SECS    5
0023 #define MAX_IPS     8192
0024 #define PAGE_OFFSET 0xffff880000000000
0025 
0026 static int map_fd;
0027 static int nr_cpus;
0028 
0029 static void usage(void)
0030 {
0031     printf("USAGE: sampleip [-F freq] [duration]\n");
0032     printf("       -F freq    # sample frequency (Hertz), default 99\n");
0033     printf("       duration   # sampling duration (seconds), default 5\n");
0034 }
0035 
0036 static int sampling_start(int freq, struct bpf_program *prog,
0037               struct bpf_link *links[])
0038 {
0039     int i, pmu_fd;
0040 
0041     struct perf_event_attr pe_sample_attr = {
0042         .type = PERF_TYPE_SOFTWARE,
0043         .freq = 1,
0044         .sample_period = freq,
0045         .config = PERF_COUNT_SW_CPU_CLOCK,
0046         .inherit = 1,
0047     };
0048 
0049     for (i = 0; i < nr_cpus; i++) {
0050         pmu_fd = sys_perf_event_open(&pe_sample_attr, -1 /* pid */, i,
0051                         -1 /* group_fd */, 0 /* flags */);
0052         if (pmu_fd < 0) {
0053             fprintf(stderr, "ERROR: Initializing perf sampling\n");
0054             return 1;
0055         }
0056         links[i] = bpf_program__attach_perf_event(prog, pmu_fd);
0057         if (libbpf_get_error(links[i])) {
0058             fprintf(stderr, "ERROR: Attach perf event\n");
0059             links[i] = NULL;
0060             close(pmu_fd);
0061             return 1;
0062         }
0063     }
0064 
0065     return 0;
0066 }
0067 
0068 static void sampling_end(struct bpf_link *links[])
0069 {
0070     int i;
0071 
0072     for (i = 0; i < nr_cpus; i++)
0073         bpf_link__destroy(links[i]);
0074 }
0075 
0076 struct ipcount {
0077     __u64 ip;
0078     __u32 count;
0079 };
0080 
0081 /* used for sorting */
0082 struct ipcount counts[MAX_IPS];
0083 
0084 static int count_cmp(const void *p1, const void *p2)
0085 {
0086     return ((struct ipcount *)p1)->count - ((struct ipcount *)p2)->count;
0087 }
0088 
0089 static void print_ip_map(int fd)
0090 {
0091     struct ksym *sym;
0092     __u64 key, next_key;
0093     __u32 value;
0094     int i, max;
0095 
0096     printf("%-19s %-32s %s\n", "ADDR", "KSYM", "COUNT");
0097 
0098     /* fetch IPs and counts */
0099     key = 0, i = 0;
0100     while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
0101         bpf_map_lookup_elem(fd, &next_key, &value);
0102         counts[i].ip = next_key;
0103         counts[i++].count = value;
0104         key = next_key;
0105     }
0106     max = i;
0107 
0108     /* sort and print */
0109     qsort(counts, max, sizeof(struct ipcount), count_cmp);
0110     for (i = 0; i < max; i++) {
0111         if (counts[i].ip > PAGE_OFFSET) {
0112             sym = ksym_search(counts[i].ip);
0113             if (!sym) {
0114                 printf("ksym not found. Is kallsyms loaded?\n");
0115                 continue;
0116             }
0117 
0118             printf("0x%-17llx %-32s %u\n", counts[i].ip, sym->name,
0119                    counts[i].count);
0120         } else {
0121             printf("0x%-17llx %-32s %u\n", counts[i].ip, "(user)",
0122                    counts[i].count);
0123         }
0124     }
0125 
0126     if (max == MAX_IPS) {
0127         printf("WARNING: IP hash was full (max %d entries); ", max);
0128         printf("may have dropped samples\n");
0129     }
0130 }
0131 
0132 static void int_exit(int sig)
0133 {
0134     printf("\n");
0135     print_ip_map(map_fd);
0136     exit(0);
0137 }
0138 
0139 int main(int argc, char **argv)
0140 {
0141     int opt, freq = DEFAULT_FREQ, secs = DEFAULT_SECS, error = 1;
0142     struct bpf_object *obj = NULL;
0143     struct bpf_program *prog;
0144     struct bpf_link **links;
0145     char filename[256];
0146 
0147     /* process arguments */
0148     while ((opt = getopt(argc, argv, "F:h")) != -1) {
0149         switch (opt) {
0150         case 'F':
0151             freq = atoi(optarg);
0152             break;
0153         case 'h':
0154         default:
0155             usage();
0156             return 0;
0157         }
0158     }
0159     if (argc - optind == 1)
0160         secs = atoi(argv[optind]);
0161     if (freq == 0 || secs == 0) {
0162         usage();
0163         return 1;
0164     }
0165 
0166     /* initialize kernel symbol translation */
0167     if (load_kallsyms()) {
0168         fprintf(stderr, "ERROR: loading /proc/kallsyms\n");
0169         return 2;
0170     }
0171 
0172     /* create perf FDs for each CPU */
0173     nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
0174     links = calloc(nr_cpus, sizeof(struct bpf_link *));
0175     if (!links) {
0176         fprintf(stderr, "ERROR: malloc of links\n");
0177         goto cleanup;
0178     }
0179 
0180     snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
0181     obj = bpf_object__open_file(filename, NULL);
0182     if (libbpf_get_error(obj)) {
0183         fprintf(stderr, "ERROR: opening BPF object file failed\n");
0184         obj = NULL;
0185         goto cleanup;
0186     }
0187 
0188     prog = bpf_object__find_program_by_name(obj, "do_sample");
0189     if (!prog) {
0190         fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
0191         goto cleanup;
0192     }
0193 
0194     /* load BPF program */
0195     if (bpf_object__load(obj)) {
0196         fprintf(stderr, "ERROR: loading BPF object file failed\n");
0197         goto cleanup;
0198     }
0199 
0200     map_fd = bpf_object__find_map_fd_by_name(obj, "ip_map");
0201     if (map_fd < 0) {
0202         fprintf(stderr, "ERROR: finding a map in obj file failed\n");
0203         goto cleanup;
0204     }
0205 
0206     signal(SIGINT, int_exit);
0207     signal(SIGTERM, int_exit);
0208 
0209     /* do sampling */
0210     printf("Sampling at %d Hertz for %d seconds. Ctrl-C also ends.\n",
0211            freq, secs);
0212     if (sampling_start(freq, prog, links) != 0)
0213         goto cleanup;
0214 
0215     sleep(secs);
0216     error = 0;
0217 
0218 cleanup:
0219     sampling_end(links);
0220     /* output sample counts */
0221     if (!error)
0222         print_ip_map(map_fd);
0223 
0224     free(links);
0225     bpf_object__close(obj);
0226     return error;
0227 }