Blame view
samples/bpf/trace_event_user.c
7.92 KB
25763b3c8 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1c47910ef samples/bpf: add ... |
2 |
/* Copyright (c) 2016 Facebook |
1c47910ef samples/bpf: add ... |
3 4 5 6 7 8 |
*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> |
1c47910ef samples/bpf: add ... |
9 10 11 |
#include <linux/perf_event.h> #include <linux/bpf.h> #include <signal.h> |
1c47910ef samples/bpf: add ... |
12 13 |
#include <errno.h> #include <sys/resource.h> |
aa5e2af66 samples, bpf: Ref... |
14 |
#include <bpf/bpf.h> |
7cf245a37 samples/bpf: Use ... |
15 |
#include <bpf/libbpf.h> |
205c8ada3 samples/bpf: Remo... |
16 |
#include "perf-sys.h" |
28dbf861d samples/bpf: move... |
17 |
#include "trace_helpers.h" |
1c47910ef samples/bpf: add ... |
18 19 |
#define SAMPLE_FREQ 50 |
aa5e2af66 samples, bpf: Ref... |
20 21 22 23 |
static int pid; /* counts, stackmap */ static int map_fd[2]; struct bpf_program *prog; |
1c47910ef samples/bpf: add ... |
24 25 26 27 28 29 30 31 32 |
static bool sys_read_seen, sys_write_seen; static void print_ksym(__u64 addr) { struct ksym *sym; if (!addr) return; sym = ksym_search(addr); |
e67b2c715 samples, selftest... |
33 34 35 36 37 |
if (!sym) { printf("ksym not found. Is kallsyms loaded? "); return; } |
1c47910ef samples/bpf: add ... |
38 |
printf("%s;", sym->name); |
bba1b2a89 samples: bpf: Rep... |
39 |
if (!strstr(sym->name, "sys_read")) |
1c47910ef samples/bpf: add ... |
40 |
sys_read_seen = true; |
bba1b2a89 samples: bpf: Rep... |
41 |
else if (!strstr(sym->name, "sys_write")) |
1c47910ef samples/bpf: add ... |
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
sys_write_seen = true; } static void print_addr(__u64 addr) { if (!addr) return; printf("%llx;", addr); } #define TASK_COMM_LEN 16 struct key_t { char comm[TASK_COMM_LEN]; __u32 kernstack; __u32 userstack; }; static void print_stack(struct key_t *key, __u64 count) { __u64 ip[PERF_MAX_STACK_DEPTH] = {}; static bool warned; int i; printf("%3lld %s;", count, key->comm); |
d40fc181e samples/bpf: Make... |
67 |
if (bpf_map_lookup_elem(map_fd[1], &key->kernstack, ip) != 0) { |
1c47910ef samples/bpf: add ... |
68 69 70 71 72 73 |
printf("---;"); } else { for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--) print_ksym(ip[i]); } printf("-;"); |
d40fc181e samples/bpf: Make... |
74 |
if (bpf_map_lookup_elem(map_fd[1], &key->userstack, ip) != 0) { |
1c47910ef samples/bpf: add ... |
75 76 77 78 79 |
printf("---;"); } else { for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--) print_addr(ip[i]); } |
41e9a8046 samples/bpf: add ... |
80 81 82 83 84 |
if (count < 6) printf("\r"); else printf(" "); |
1c47910ef samples/bpf: add ... |
85 86 87 88 89 90 91 92 93 94 |
if (key->kernstack == -EEXIST && !warned) { printf("stackmap collisions seen. Consider increasing size "); warned = true; } else if ((int)key->kernstack < 0 && (int)key->userstack < 0) { printf("err stackid %d %d ", key->kernstack, key->userstack); } } |
aa5e2af66 samples, bpf: Ref... |
95 |
static void err_exit(int err) |
1c47910ef samples/bpf: add ... |
96 |
{ |
aa5e2af66 samples, bpf: Ref... |
97 98 |
kill(pid, SIGKILL); exit(err); |
1c47910ef samples/bpf: add ... |
99 100 101 102 103 104 105 |
} static void print_stacks(void) { struct key_t key = {}, next_key; __u64 value; __u32 stackid = 0, next_id; |
aa5e2af66 samples, bpf: Ref... |
106 |
int error = 1, fd = map_fd[0], stack_map = map_fd[1]; |
1c47910ef samples/bpf: add ... |
107 108 |
sys_read_seen = sys_write_seen = false; |
d40fc181e samples/bpf: Make... |
109 110 |
while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { bpf_map_lookup_elem(fd, &next_key, &value); |
1c47910ef samples/bpf: add ... |
111 |
print_stack(&next_key, value); |
d40fc181e samples/bpf: Make... |
112 |
bpf_map_delete_elem(fd, &next_key); |
1c47910ef samples/bpf: add ... |
113 114 |
key = next_key; } |
41e9a8046 samples/bpf: add ... |
115 116 |
printf(" "); |
1c47910ef samples/bpf: add ... |
117 118 119 |
if (!sys_read_seen || !sys_write_seen) { printf("BUG kernel stack doesn't contain sys_read() and sys_write() "); |
aa5e2af66 samples, bpf: Ref... |
120 |
err_exit(error); |
1c47910ef samples/bpf: add ... |
121 122 123 |
} /* clear stack map */ |
d40fc181e samples/bpf: Make... |
124 125 |
while (bpf_map_get_next_key(stack_map, &stackid, &next_id) == 0) { bpf_map_delete_elem(stack_map, &next_id); |
1c47910ef samples/bpf: add ... |
126 127 128 |
stackid = next_id; } } |
492b7e894 samples/bpf: Chec... |
129 130 131 132 133 134 135 136 137 138 |
static inline int generate_load(void) { if (system("dd if=/dev/zero of=/dev/null count=5000k status=none") < 0) { printf("failed to generate some load with dd: %s ", strerror(errno)); return -1; } return 0; } |
1c47910ef samples/bpf: add ... |
139 140 |
static void test_perf_event_all_cpu(struct perf_event_attr *attr) { |
aa5e2af66 samples, bpf: Ref... |
141 142 143 144 145 146 147 148 149 |
int nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); struct bpf_link **links = calloc(nr_cpus, sizeof(struct bpf_link *)); int i, pmu_fd, error = 1; if (!links) { printf("malloc of links failed "); goto err; } |
1c47910ef samples/bpf: add ... |
150 |
|
81b9cf802 bpf: add a test c... |
151 152 |
/* system wide perf event, no need to inherit */ attr->inherit = 0; |
1c47910ef samples/bpf: add ... |
153 154 |
/* open perf_event on all cpus */ for (i = 0; i < nr_cpus; i++) { |
aa5e2af66 samples, bpf: Ref... |
155 156 |
pmu_fd = sys_perf_event_open(attr, -1, i, -1, 0); if (pmu_fd < 0) { |
205c8ada3 samples/bpf: Remo... |
157 158 |
printf("sys_perf_event_open failed "); |
1c47910ef samples/bpf: add ... |
159 160 |
goto all_cpu_err; } |
aa5e2af66 samples, bpf: Ref... |
161 |
links[i] = bpf_program__attach_perf_event(prog, pmu_fd); |
0efdcefb0 samples, bpf: Ref... |
162 |
if (libbpf_get_error(links[i])) { |
aa5e2af66 samples, bpf: Ref... |
163 164 165 166 167 168 |
printf("bpf_program__attach_perf_event failed "); links[i] = NULL; close(pmu_fd); goto all_cpu_err; } |
1c47910ef samples/bpf: add ... |
169 |
} |
492b7e894 samples/bpf: Chec... |
170 |
|
aa5e2af66 samples, bpf: Ref... |
171 |
if (generate_load() < 0) |
492b7e894 samples/bpf: Chec... |
172 |
goto all_cpu_err; |
aa5e2af66 samples, bpf: Ref... |
173 |
|
1c47910ef samples/bpf: add ... |
174 |
print_stacks(); |
aa5e2af66 samples, bpf: Ref... |
175 |
error = 0; |
1c47910ef samples/bpf: add ... |
176 |
all_cpu_err: |
aa5e2af66 samples, bpf: Ref... |
177 178 179 180 |
for (i--; i >= 0; i--) bpf_link__destroy(links[i]); err: free(links); |
41e9a8046 samples/bpf: add ... |
181 |
if (error) |
aa5e2af66 samples, bpf: Ref... |
182 |
err_exit(error); |
1c47910ef samples/bpf: add ... |
183 184 185 186 |
} static void test_perf_event_task(struct perf_event_attr *attr) { |
aa5e2af66 samples, bpf: Ref... |
187 188 |
struct bpf_link *link = NULL; int pmu_fd, error = 1; |
1c47910ef samples/bpf: add ... |
189 |
|
81b9cf802 bpf: add a test c... |
190 191 192 193 |
/* per task perf event, enable inherit so the "dd ..." command can be traced properly. * Enabling inherit will cause bpf_perf_prog_read_time helper failure. */ attr->inherit = 1; |
1c47910ef samples/bpf: add ... |
194 |
/* open task bound event */ |
205c8ada3 samples/bpf: Remo... |
195 |
pmu_fd = sys_perf_event_open(attr, 0, -1, -1, 0); |
1c47910ef samples/bpf: add ... |
196 |
if (pmu_fd < 0) { |
205c8ada3 samples/bpf: Remo... |
197 198 |
printf("sys_perf_event_open failed "); |
aa5e2af66 samples, bpf: Ref... |
199 |
goto err; |
1c47910ef samples/bpf: add ... |
200 |
} |
aa5e2af66 samples, bpf: Ref... |
201 |
link = bpf_program__attach_perf_event(prog, pmu_fd); |
0efdcefb0 samples, bpf: Ref... |
202 |
if (libbpf_get_error(link)) { |
aa5e2af66 samples, bpf: Ref... |
203 204 205 206 |
printf("bpf_program__attach_perf_event failed "); link = NULL; close(pmu_fd); |
492b7e894 samples/bpf: Chec... |
207 208 |
goto err; } |
aa5e2af66 samples, bpf: Ref... |
209 210 211 |
if (generate_load() < 0) goto err; |
1c47910ef samples/bpf: add ... |
212 |
print_stacks(); |
aa5e2af66 samples, bpf: Ref... |
213 |
error = 0; |
492b7e894 samples/bpf: Chec... |
214 |
err: |
aa5e2af66 samples, bpf: Ref... |
215 |
bpf_link__destroy(link); |
492b7e894 samples/bpf: Chec... |
216 |
if (error) |
aa5e2af66 samples, bpf: Ref... |
217 |
err_exit(error); |
1c47910ef samples/bpf: add ... |
218 219 220 221 222 223 224 225 226 |
} static void test_bpf_perf_event(void) { struct perf_event_attr attr_type_hw = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, |
1c47910ef samples/bpf: add ... |
227 228 229 230 231 232 |
}; struct perf_event_attr attr_type_sw = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, |
1c47910ef samples/bpf: add ... |
233 |
}; |
41e9a8046 samples/bpf: add ... |
234 235 236 237 238 239 240 241 |
struct perf_event_attr attr_hw_cache_l1d = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_HW_CACHE, .config = PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), |
41e9a8046 samples/bpf: add ... |
242 243 244 245 246 247 248 249 250 |
}; struct perf_event_attr attr_hw_cache_branch_miss = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_HW_CACHE, .config = PERF_COUNT_HW_CACHE_BPU | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), |
41e9a8046 samples/bpf: add ... |
251 252 253 254 255 256 257 |
}; struct perf_event_attr attr_type_raw = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_RAW, /* Intel Instruction Retired */ .config = 0xc0, |
41e9a8046 samples/bpf: add ... |
258 |
}; |
12fe12253 samples/bpf: add ... |
259 260 261 262 263 264 265 266 267 268 269 |
struct perf_event_attr attr_type_raw_lock_load = { .sample_freq = SAMPLE_FREQ, .freq = 1, .type = PERF_TYPE_RAW, /* Intel MEM_UOPS_RETIRED.LOCK_LOADS */ .config = 0x21d0, /* Request to record lock address from PEBS */ .sample_type = PERF_SAMPLE_ADDR, /* Record address value requires precise event */ .precise_ip = 2, }; |
1c47910ef samples/bpf: add ... |
270 |
|
41e9a8046 samples/bpf: add ... |
271 272 |
printf("Test HW_CPU_CYCLES "); |
1c47910ef samples/bpf: add ... |
273 274 |
test_perf_event_all_cpu(&attr_type_hw); test_perf_event_task(&attr_type_hw); |
41e9a8046 samples/bpf: add ... |
275 276 277 |
printf("Test SW_CPU_CLOCK "); |
1c47910ef samples/bpf: add ... |
278 279 |
test_perf_event_all_cpu(&attr_type_sw); test_perf_event_task(&attr_type_sw); |
41e9a8046 samples/bpf: add ... |
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
printf("Test HW_CACHE_L1D "); test_perf_event_all_cpu(&attr_hw_cache_l1d); test_perf_event_task(&attr_hw_cache_l1d); printf("Test HW_CACHE_BPU "); test_perf_event_all_cpu(&attr_hw_cache_branch_miss); test_perf_event_task(&attr_hw_cache_branch_miss); printf("Test Instruction Retired "); test_perf_event_all_cpu(&attr_type_raw); test_perf_event_task(&attr_type_raw); |
12fe12253 samples/bpf: add ... |
295 296 297 298 |
printf("Test Lock Load "); test_perf_event_all_cpu(&attr_type_raw_lock_load); test_perf_event_task(&attr_type_raw_lock_load); |
41e9a8046 samples/bpf: add ... |
299 300 |
printf("*** PASS *** "); |
1c47910ef samples/bpf: add ... |
301 302 303 304 305 306 |
} int main(int argc, char **argv) { struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; |
aa5e2af66 samples, bpf: Ref... |
307 |
struct bpf_object *obj = NULL; |
1c47910ef samples/bpf: add ... |
308 |
char filename[256]; |
aa5e2af66 samples, bpf: Ref... |
309 |
int error = 1; |
1c47910ef samples/bpf: add ... |
310 311 312 |
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); setrlimit(RLIMIT_MEMLOCK, &r); |
aa5e2af66 samples, bpf: Ref... |
313 314 |
signal(SIGINT, err_exit); signal(SIGTERM, err_exit); |
1c47910ef samples/bpf: add ... |
315 316 317 318 |
if (load_kallsyms()) { printf("failed to process /proc/kallsyms "); |
aa5e2af66 samples, bpf: Ref... |
319 320 321 322 |
goto cleanup; } obj = bpf_object__open_file(filename, NULL); |
0efdcefb0 samples, bpf: Ref... |
323 |
if (libbpf_get_error(obj)) { |
aa5e2af66 samples, bpf: Ref... |
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
printf("opening BPF object file failed "); obj = NULL; goto cleanup; } prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); if (!prog) { printf("finding a prog in obj file failed "); goto cleanup; } /* load BPF program */ if (bpf_object__load(obj)) { printf("loading BPF object file failed "); goto cleanup; |
1c47910ef samples/bpf: add ... |
342 |
} |
aa5e2af66 samples, bpf: Ref... |
343 344 345 346 347 348 |
map_fd[0] = bpf_object__find_map_fd_by_name(obj, "counts"); map_fd[1] = bpf_object__find_map_fd_by_name(obj, "stackmap"); if (map_fd[0] < 0 || map_fd[1] < 0) { printf("finding a counts/stackmap map in obj file failed "); goto cleanup; |
1c47910ef samples/bpf: add ... |
349 |
} |
aa5e2af66 samples, bpf: Ref... |
350 351 |
pid = fork(); if (pid == 0) { |
1c47910ef samples/bpf: add ... |
352 353 |
read_trace_pipe(); return 0; |
aa5e2af66 samples, bpf: Ref... |
354 355 356 357 |
} else if (pid == -1) { printf("couldn't spawn process "); goto cleanup; |
1c47910ef samples/bpf: add ... |
358 |
} |
aa5e2af66 samples, bpf: Ref... |
359 |
|
1c47910ef samples/bpf: add ... |
360 |
test_bpf_perf_event(); |
aa5e2af66 samples, bpf: Ref... |
361 362 363 364 365 |
error = 0; cleanup: bpf_object__close(obj); err_exit(error); |
1c47910ef samples/bpf: add ... |
366 |
} |