0001
0002
0003
0004
0005
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 , i,
0051 -1 , 0 );
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
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
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
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
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
0167 if (load_kallsyms()) {
0168 fprintf(stderr, "ERROR: loading /proc/kallsyms\n");
0169 return 2;
0170 }
0171
0172
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
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
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
0221 if (!error)
0222 print_ip_map(map_fd);
0223
0224 free(links);
0225 bpf_object__close(obj);
0226 return error;
0227 }