diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-10-30 05:09:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-10-30 05:09:37 -0400 |
commit | bebd23a2ed31d47e7dd746d3b125068aa2c42d85 (patch) | |
tree | 81cc1a59203c393286dba3e76daa343f5c35b127 | |
parent | 66a565c203bc31b76969711fbd92da11bee2f129 (diff) | |
parent | 7ed4915ad60788d6b846e2cd034f49ee15698143 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
- Allow passing C language eBPF scriptlets via --event in all tools,
so that it gets built using clang and then pass it to the kernel via
sys_bpf(). (Wang Nan)
- Wire up the loaded ebpf object file with associated kprobes, so that
it can determine if the kprobes will be filtered or not. (Wang Nan)
User visible changes:
- Add cmd string table to decode sys_bpf first arg in 'trace'. (Arnaldo Carvalho de Melo)
- Enable printing of branch stack in 'perf script'. (Stephane Eranian)
- Pass the right file with debug info to libunwind. (Rabin Vincent)
Build Fixes:
- Make sure fixdep is built before libbpf, fixing a race. (Jiri Olsa)
- Fix libiberty feature detection. (Rabin Vincent)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/build/feature/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 6 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-script.txt | 14 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 2 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 7 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 82 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 7 | ||||
-rw-r--r-- | tools/perf/tests/bpf-script-example.c | 44 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.c | 17 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.h | 5 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 17 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 1 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 11 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.y | 15 | ||||
-rw-r--r-- | tools/perf/util/unwind-libunwind.c | 5 |
17 files changed, 227 insertions, 16 deletions
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index e43a2971bf56..cea04ce9f35c 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile | |||
@@ -132,10 +132,10 @@ test-libbfd.bin: | |||
132 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl | 132 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl |
133 | 133 | ||
134 | test-liberty.bin: | 134 | test-liberty.bin: |
135 | $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty | 135 | $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty |
136 | 136 | ||
137 | test-liberty-z.bin: | 137 | test-liberty-z.bin: |
138 | $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz | 138 | $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz |
139 | 139 | ||
140 | test-cplus-demangle.bin: | 140 | test-cplus-demangle.bin: |
141 | $(BUILD) -liberty | 141 | $(BUILD) -liberty |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 7ff6a9d0ea0d..e630a7d2c348 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -314,6 +314,12 @@ This option sets the time out limit. The default value is 500 ms. | |||
314 | Record context switch events i.e. events of type PERF_RECORD_SWITCH or | 314 | Record context switch events i.e. events of type PERF_RECORD_SWITCH or |
315 | PERF_RECORD_SWITCH_CPU_WIDE. | 315 | PERF_RECORD_SWITCH_CPU_WIDE. |
316 | 316 | ||
317 | --clang-path:: | ||
318 | Path to clang binary to use for compiling BPF scriptlets. | ||
319 | |||
320 | --clang-opt:: | ||
321 | Options passed to clang when compiling BPF scriptlets. | ||
322 | |||
317 | SEE ALSO | 323 | SEE ALSO |
318 | -------- | 324 | -------- |
319 | linkperf:perf-stat[1], linkperf:perf-list[1] | 325 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index b3b42f9285df..382ddfb45d1d 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -112,11 +112,11 @@ OPTIONS | |||
112 | --debug-mode:: | 112 | --debug-mode:: |
113 | Do various checks like samples ordering and lost events. | 113 | Do various checks like samples ordering and lost events. |
114 | 114 | ||
115 | -f:: | 115 | -F:: |
116 | --fields:: | 116 | --fields:: |
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, |
119 | srcline, period, iregs, flags. | 119 | srcline, period, iregs, brstack, brstacksym, flags. |
120 | Field list can be prepended with the type, trace, sw or hw, | 120 | Field list can be prepended with the type, trace, sw or hw, |
121 | to indicate to which event type the field list applies. | 121 | to indicate to which event type the field list applies. |
122 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace | 122 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace |
@@ -175,6 +175,16 @@ OPTIONS | |||
175 | Finally, a user may not set fields to none for all event types. | 175 | Finally, a user may not set fields to none for all event types. |
176 | i.e., -f "" is not allowed. | 176 | i.e., -f "" is not allowed. |
177 | 177 | ||
178 | The brstack output includes branch related information with raw addresses using the | ||
179 | /v/v/v/v/ syntax in the following order: | ||
180 | FROM: branch source instruction | ||
181 | TO : branch target instruction | ||
182 | M/P/-: M=branch target mispredicted or branch direction was mispredicted, P=target predicted or direction predicted, -=not supported | ||
183 | X/- : X=branch inside a transactional region, -=not in transaction region or not supported | ||
184 | A/- : A=TSX abort entry, -=not aborted region or not supported | ||
185 | |||
186 | The brstacksym is identical to brstack, except that the FROM and TO addresses are printed in a symbolic form if possible. | ||
187 | |||
178 | -k:: | 188 | -k:: |
179 | --vmlinux=<file>:: | 189 | --vmlinux=<file>:: |
180 | vmlinux pathname | 190 | vmlinux pathname |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 1e2e2d1d26b7..0d19d5447d6c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -430,7 +430,7 @@ $(LIBAPI)-clean: | |||
430 | $(call QUIET_CLEAN, libapi) | 430 | $(call QUIET_CLEAN, libapi) |
431 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null | 431 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
432 | 432 | ||
433 | $(LIBBPF): FORCE | 433 | $(LIBBPF): fixdep FORCE |
434 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a | 434 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a |
435 | 435 | ||
436 | $(LIBBPF)-clean: | 436 | $(LIBBPF)-clean: |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index de02267c73d8..199fc31e3919 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "util/auxtrace.h" | 31 | #include "util/auxtrace.h" |
32 | #include "util/parse-branch-options.h" | 32 | #include "util/parse-branch-options.h" |
33 | #include "util/parse-regs-options.h" | 33 | #include "util/parse-regs-options.h" |
34 | #include "util/llvm-utils.h" | ||
34 | 35 | ||
35 | #include <unistd.h> | 36 | #include <unistd.h> |
36 | #include <sched.h> | 37 | #include <sched.h> |
@@ -1112,6 +1113,12 @@ struct option __record_options[] = { | |||
1112 | "per thread proc mmap processing timeout in ms"), | 1113 | "per thread proc mmap processing timeout in ms"), |
1113 | OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, | 1114 | OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, |
1114 | "Record context switch events"), | 1115 | "Record context switch events"), |
1116 | #ifdef HAVE_LIBBPF_SUPPORT | ||
1117 | OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", | ||
1118 | "clang binary to use for compiling BPF scriptlets"), | ||
1119 | OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", | ||
1120 | "options passed to clang when compiling BPF scriptlets"), | ||
1121 | #endif | ||
1115 | OPT_END() | 1122 | OPT_END() |
1116 | }; | 1123 | }; |
1117 | 1124 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 278acb22f029..72b5deb4bd79 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -51,6 +51,8 @@ enum perf_output_field { | |||
51 | PERF_OUTPUT_SRCLINE = 1U << 12, | 51 | PERF_OUTPUT_SRCLINE = 1U << 12, |
52 | PERF_OUTPUT_PERIOD = 1U << 13, | 52 | PERF_OUTPUT_PERIOD = 1U << 13, |
53 | PERF_OUTPUT_IREGS = 1U << 14, | 53 | PERF_OUTPUT_IREGS = 1U << 14, |
54 | PERF_OUTPUT_BRSTACK = 1U << 15, | ||
55 | PERF_OUTPUT_BRSTACKSYM = 1U << 16, | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | struct output_option { | 58 | struct output_option { |
@@ -72,6 +74,8 @@ struct output_option { | |||
72 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, | 74 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, |
73 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, | 75 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, |
74 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, | 76 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, |
77 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, | ||
78 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, | ||
75 | }; | 79 | }; |
76 | 80 | ||
77 | /* default set to maintain compatibility with current format */ | 81 | /* default set to maintain compatibility with current format */ |
@@ -425,6 +429,77 @@ static void print_sample_start(struct perf_sample *sample, | |||
425 | } | 429 | } |
426 | } | 430 | } |
427 | 431 | ||
432 | static inline char | ||
433 | mispred_str(struct branch_entry *br) | ||
434 | { | ||
435 | if (!(br->flags.mispred || br->flags.predicted)) | ||
436 | return '-'; | ||
437 | |||
438 | return br->flags.predicted ? 'P' : 'M'; | ||
439 | } | ||
440 | |||
441 | static void print_sample_brstack(union perf_event *event __maybe_unused, | ||
442 | struct perf_sample *sample, | ||
443 | struct thread *thread __maybe_unused, | ||
444 | struct perf_event_attr *attr __maybe_unused) | ||
445 | { | ||
446 | struct branch_stack *br = sample->branch_stack; | ||
447 | u64 i; | ||
448 | |||
449 | if (!(br && br->nr)) | ||
450 | return; | ||
451 | |||
452 | for (i = 0; i < br->nr; i++) { | ||
453 | printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ", | ||
454 | br->entries[i].from, | ||
455 | br->entries[i].to, | ||
456 | mispred_str( br->entries + i), | ||
457 | br->entries[i].flags.in_tx? 'X' : '-', | ||
458 | br->entries[i].flags.abort? 'A' : '-', | ||
459 | br->entries[i].flags.cycles); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | static void print_sample_brstacksym(union perf_event *event __maybe_unused, | ||
464 | struct perf_sample *sample, | ||
465 | struct thread *thread __maybe_unused, | ||
466 | struct perf_event_attr *attr __maybe_unused) | ||
467 | { | ||
468 | struct branch_stack *br = sample->branch_stack; | ||
469 | struct addr_location alf, alt; | ||
470 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
471 | u64 i, from, to; | ||
472 | |||
473 | if (!(br && br->nr)) | ||
474 | return; | ||
475 | |||
476 | for (i = 0; i < br->nr; i++) { | ||
477 | |||
478 | memset(&alf, 0, sizeof(alf)); | ||
479 | memset(&alt, 0, sizeof(alt)); | ||
480 | from = br->entries[i].from; | ||
481 | to = br->entries[i].to; | ||
482 | |||
483 | thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf); | ||
484 | if (alf.map) | ||
485 | alf.sym = map__find_symbol(alf.map, alf.addr, NULL); | ||
486 | |||
487 | thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt); | ||
488 | if (alt.map) | ||
489 | alt.sym = map__find_symbol(alt.map, alt.addr, NULL); | ||
490 | |||
491 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); | ||
492 | putchar('/'); | ||
493 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); | ||
494 | printf("/%c/%c/%c/%d ", | ||
495 | mispred_str( br->entries + i), | ||
496 | br->entries[i].flags.in_tx? 'X' : '-', | ||
497 | br->entries[i].flags.abort? 'A' : '-', | ||
498 | br->entries[i].flags.cycles); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | |||
428 | static void print_sample_addr(union perf_event *event, | 503 | static void print_sample_addr(union perf_event *event, |
429 | struct perf_sample *sample, | 504 | struct perf_sample *sample, |
430 | struct thread *thread, | 505 | struct thread *thread, |
@@ -560,6 +635,11 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
560 | if (PRINT_FIELD(IREGS)) | 635 | if (PRINT_FIELD(IREGS)) |
561 | print_sample_iregs(event, sample, thread, attr); | 636 | print_sample_iregs(event, sample, thread, attr); |
562 | 637 | ||
638 | if (PRINT_FIELD(BRSTACK)) | ||
639 | print_sample_brstack(event, sample, thread, attr); | ||
640 | else if (PRINT_FIELD(BRSTACKSYM)) | ||
641 | print_sample_brstacksym(event, sample, thread, attr); | ||
642 | |||
563 | printf("\n"); | 643 | printf("\n"); |
564 | } | 644 | } |
565 | 645 | ||
@@ -1681,7 +1761,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1681 | "comma separated output fields prepend with 'type:'. " | 1761 | "comma separated output fields prepend with 'type:'. " |
1682 | "Valid types: hw,sw,trace,raw. " | 1762 | "Valid types: hw,sw,trace,raw. " |
1683 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 1763 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
1684 | "addr,symoff,period,iregs,flags", parse_output_fields), | 1764 | "addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields), |
1685 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1765 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1686 | "system-wide collection from all CPUs"), | 1766 | "system-wide collection from all CPUs"), |
1687 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1767 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 93b80f12f35e..c783d8fd3a80 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -585,6 +585,12 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct sysc | |||
585 | 585 | ||
586 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op | 586 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op |
587 | 587 | ||
588 | static const char *bpf_cmd[] = { | ||
589 | "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", | ||
590 | "MAP_GET_NEXT_KEY", "PROG_LOAD", | ||
591 | }; | ||
592 | static DEFINE_STRARRAY(bpf_cmd); | ||
593 | |||
588 | static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", }; | 594 | static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", }; |
589 | static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1); | 595 | static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1); |
590 | 596 | ||
@@ -1011,6 +1017,7 @@ static struct syscall_fmt { | |||
1011 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ | 1017 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ |
1012 | [1] = SCA_ACCMODE, /* mode */ }, }, | 1018 | [1] = SCA_ACCMODE, /* mode */ }, }, |
1013 | { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, | 1019 | { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, |
1020 | { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), }, | ||
1014 | { .name = "brk", .hexret = true, | 1021 | { .name = "brk", .hexret = true, |
1015 | .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, | 1022 | .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, |
1016 | { .name = "chdir", .errmsg = true, | 1023 | { .name = "chdir", .errmsg = true, |
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c new file mode 100644 index 000000000000..410a70b93b93 --- /dev/null +++ b/tools/perf/tests/bpf-script-example.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef LINUX_VERSION_CODE | ||
2 | # error Need LINUX_VERSION_CODE | ||
3 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' | ||
4 | #endif | ||
5 | #define BPF_ANY 0 | ||
6 | #define BPF_MAP_TYPE_ARRAY 2 | ||
7 | #define BPF_FUNC_map_lookup_elem 1 | ||
8 | #define BPF_FUNC_map_update_elem 2 | ||
9 | |||
10 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = | ||
11 | (void *) BPF_FUNC_map_lookup_elem; | ||
12 | static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = | ||
13 | (void *) BPF_FUNC_map_update_elem; | ||
14 | |||
15 | struct bpf_map_def { | ||
16 | unsigned int type; | ||
17 | unsigned int key_size; | ||
18 | unsigned int value_size; | ||
19 | unsigned int max_entries; | ||
20 | }; | ||
21 | |||
22 | #define SEC(NAME) __attribute__((section(NAME), used)) | ||
23 | struct bpf_map_def SEC("maps") flip_table = { | ||
24 | .type = BPF_MAP_TYPE_ARRAY, | ||
25 | .key_size = sizeof(int), | ||
26 | .value_size = sizeof(int), | ||
27 | .max_entries = 1, | ||
28 | }; | ||
29 | |||
30 | SEC("func=sys_epoll_pwait") | ||
31 | int bpf_func__sys_epoll_pwait(void *ctx) | ||
32 | { | ||
33 | int ind =0; | ||
34 | int *flag = bpf_map_lookup_elem(&flip_table, &ind); | ||
35 | int new_flag; | ||
36 | if (!flag) | ||
37 | return 0; | ||
38 | /* flip flag and store back */ | ||
39 | new_flag = !*flag; | ||
40 | bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); | ||
41 | return new_flag; | ||
42 | } | ||
43 | char _license[] SEC("license") = "GPL"; | ||
44 | int _version SEC("version") = LINUX_VERSION_CODE; | ||
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index aa784a498c48..ba6f7526b282 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "bpf-loader.h" | 12 | #include "bpf-loader.h" |
13 | #include "probe-event.h" | 13 | #include "probe-event.h" |
14 | #include "probe-finder.h" // for MAX_PROBES | 14 | #include "probe-finder.h" // for MAX_PROBES |
15 | #include "llvm-utils.h" | ||
15 | 16 | ||
16 | #define DEFINE_PRINT_FN(name, level) \ | 17 | #define DEFINE_PRINT_FN(name, level) \ |
17 | static int libbpf_##name(const char *fmt, ...) \ | 18 | static int libbpf_##name(const char *fmt, ...) \ |
@@ -33,7 +34,7 @@ struct bpf_prog_priv { | |||
33 | struct perf_probe_event pev; | 34 | struct perf_probe_event pev; |
34 | }; | 35 | }; |
35 | 36 | ||
36 | struct bpf_object *bpf__prepare_load(const char *filename) | 37 | struct bpf_object *bpf__prepare_load(const char *filename, bool source) |
37 | { | 38 | { |
38 | struct bpf_object *obj; | 39 | struct bpf_object *obj; |
39 | static bool libbpf_initialized; | 40 | static bool libbpf_initialized; |
@@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename) | |||
45 | libbpf_initialized = true; | 46 | libbpf_initialized = true; |
46 | } | 47 | } |
47 | 48 | ||
48 | obj = bpf_object__open(filename); | 49 | if (source) { |
50 | int err; | ||
51 | void *obj_buf; | ||
52 | size_t obj_buf_sz; | ||
53 | |||
54 | err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); | ||
55 | if (err) | ||
56 | return ERR_PTR(err); | ||
57 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); | ||
58 | free(obj_buf); | ||
59 | } else | ||
60 | obj = bpf_object__open(filename); | ||
61 | |||
49 | if (!obj) { | 62 | if (!obj) { |
50 | pr_debug("bpf: failed to load %s\n", filename); | 63 | pr_debug("bpf: failed to load %s\n", filename); |
51 | return ERR_PTR(-EINVAL); | 64 | return ERR_PTR(-EINVAL); |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index a8f25ee06fc5..ccd8d7fd79d3 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
@@ -18,7 +18,7 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, | |||
18 | int fd, void *arg); | 18 | int fd, void *arg); |
19 | 19 | ||
20 | #ifdef HAVE_LIBBPF_SUPPORT | 20 | #ifdef HAVE_LIBBPF_SUPPORT |
21 | struct bpf_object *bpf__prepare_load(const char *filename); | 21 | struct bpf_object *bpf__prepare_load(const char *filename, bool source); |
22 | 22 | ||
23 | void bpf__clear(void); | 23 | void bpf__clear(void); |
24 | 24 | ||
@@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
34 | bpf_prog_iter_callback_t func, void *arg); | 34 | bpf_prog_iter_callback_t func, void *arg); |
35 | #else | 35 | #else |
36 | static inline struct bpf_object * | 36 | static inline struct bpf_object * |
37 | bpf__prepare_load(const char *filename __maybe_unused) | 37 | bpf__prepare_load(const char *filename __maybe_unused, |
38 | bool source __maybe_unused) | ||
38 | { | 39 | { |
39 | pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); | 40 | pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); |
40 | return ERR_PTR(-ENOTSUP); | 41 | return ERR_PTR(-ENOTSUP); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3ac4ee9c6a6e..397fb4ed3c97 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -208,6 +208,7 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
208 | evsel->unit = ""; | 208 | evsel->unit = ""; |
209 | evsel->scale = 1.0; | 209 | evsel->scale = 1.0; |
210 | evsel->evlist = NULL; | 210 | evsel->evlist = NULL; |
211 | evsel->bpf_fd = -1; | ||
211 | INIT_LIST_HEAD(&evsel->node); | 212 | INIT_LIST_HEAD(&evsel->node); |
212 | INIT_LIST_HEAD(&evsel->config_terms); | 213 | INIT_LIST_HEAD(&evsel->config_terms); |
213 | perf_evsel__object.init(evsel); | 214 | perf_evsel__object.init(evsel); |
@@ -1356,6 +1357,22 @@ retry_open: | |||
1356 | err); | 1357 | err); |
1357 | goto try_fallback; | 1358 | goto try_fallback; |
1358 | } | 1359 | } |
1360 | |||
1361 | if (evsel->bpf_fd >= 0) { | ||
1362 | int evt_fd = FD(evsel, cpu, thread); | ||
1363 | int bpf_fd = evsel->bpf_fd; | ||
1364 | |||
1365 | err = ioctl(evt_fd, | ||
1366 | PERF_EVENT_IOC_SET_BPF, | ||
1367 | bpf_fd); | ||
1368 | if (err && errno != EEXIST) { | ||
1369 | pr_err("failed to attach bpf fd %d: %s\n", | ||
1370 | bpf_fd, strerror(errno)); | ||
1371 | err = -EINVAL; | ||
1372 | goto out_close; | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1359 | set_rlimit = NO_CHANGE; | 1376 | set_rlimit = NO_CHANGE; |
1360 | 1377 | ||
1361 | /* | 1378 | /* |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1e8ff1906f71..0e49bd742c63 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -123,6 +123,7 @@ struct perf_evsel { | |||
123 | char *group_name; | 123 | char *group_name; |
124 | bool cmdline_group_boundary; | 124 | bool cmdline_group_boundary; |
125 | struct list_head config_terms; | 125 | struct list_head config_terms; |
126 | int bpf_fd; | ||
126 | }; | 127 | }; |
127 | 128 | ||
128 | union u64_swap { | 129 | union u64_swap { |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d97b03710331..bee60583839a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -542,6 +542,7 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, | |||
542 | struct __add_bpf_event_param *param = _param; | 542 | struct __add_bpf_event_param *param = _param; |
543 | struct parse_events_evlist *evlist = param->data; | 543 | struct parse_events_evlist *evlist = param->data; |
544 | struct list_head *list = param->list; | 544 | struct list_head *list = param->list; |
545 | struct perf_evsel *pos; | ||
545 | int err; | 546 | int err; |
546 | 547 | ||
547 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", | 548 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", |
@@ -562,6 +563,11 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, | |||
562 | } | 563 | } |
563 | pr_debug("adding %s:%s\n", tev->group, tev->event); | 564 | pr_debug("adding %s:%s\n", tev->group, tev->event); |
564 | 565 | ||
566 | list_for_each_entry(pos, &new_evsels, node) { | ||
567 | pr_debug("adding %s:%s to %p\n", | ||
568 | tev->group, tev->event, pos); | ||
569 | pos->bpf_fd = fd; | ||
570 | } | ||
565 | list_splice(&new_evsels, list); | 571 | list_splice(&new_evsels, list); |
566 | return 0; | 572 | return 0; |
567 | } | 573 | } |
@@ -620,11 +626,12 @@ errout: | |||
620 | 626 | ||
621 | int parse_events_load_bpf(struct parse_events_evlist *data, | 627 | int parse_events_load_bpf(struct parse_events_evlist *data, |
622 | struct list_head *list, | 628 | struct list_head *list, |
623 | char *bpf_file_name) | 629 | char *bpf_file_name, |
630 | bool source) | ||
624 | { | 631 | { |
625 | struct bpf_object *obj; | 632 | struct bpf_object *obj; |
626 | 633 | ||
627 | obj = bpf__prepare_load(bpf_file_name); | 634 | obj = bpf__prepare_load(bpf_file_name, source); |
628 | if (IS_ERR(obj) || !obj) { | 635 | if (IS_ERR(obj) || !obj) { |
629 | char errbuf[BUFSIZ]; | 636 | char errbuf[BUFSIZ]; |
630 | int err; | 637 | int err; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 765018a17448..f1a6db107241 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -125,7 +125,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, | |||
125 | struct list_head *head_config); | 125 | struct list_head *head_config); |
126 | int parse_events_load_bpf(struct parse_events_evlist *data, | 126 | int parse_events_load_bpf(struct parse_events_evlist *data, |
127 | struct list_head *list, | 127 | struct list_head *list, |
128 | char *bpf_file_name); | 128 | char *bpf_file_name, |
129 | bool source); | ||
129 | /* Provide this function for perf test */ | 130 | /* Provide this function for perf test */ |
130 | struct bpf_object; | 131 | struct bpf_object; |
131 | int parse_events_load_bpf_obj(struct parse_events_evlist *data, | 132 | int parse_events_load_bpf_obj(struct parse_events_evlist *data, |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index cf330ebf812c..58c5831ffd5c 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]* | |||
116 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* | 116 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* |
117 | event [^,{}/]+ | 117 | event [^,{}/]+ |
118 | bpf_object .*\.(o|bpf) | 118 | bpf_object .*\.(o|bpf) |
119 | bpf_source .*\.c | ||
119 | 120 | ||
120 | num_dec [0-9]+ | 121 | num_dec [0-9]+ |
121 | num_hex 0x[a-fA-F0-9]+ | 122 | num_hex 0x[a-fA-F0-9]+ |
@@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3} | |||
161 | 162 | ||
162 | {event_pmu} | | 163 | {event_pmu} | |
163 | {bpf_object} | | 164 | {bpf_object} | |
165 | {bpf_source} | | ||
164 | {event} { | 166 | {event} { |
165 | BEGIN(INITIAL); | 167 | BEGIN(INITIAL); |
166 | REWIND(1); | 168 | REWIND(1); |
@@ -269,6 +271,7 @@ r{num_raw_hex} { return raw(yyscanner); } | |||
269 | 271 | ||
270 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } | 272 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
271 | {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } | 273 | {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } |
274 | {bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } | ||
272 | {name} { return pmu_str_check(yyscanner); } | 275 | {name} { return pmu_str_check(yyscanner); } |
273 | "/" { BEGIN(config); return '/'; } | 276 | "/" { BEGIN(config); return '/'; } |
274 | - { return '-'; } | 277 | - { return '-'; } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 497f19b20f0b..ad379968d4c1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -42,7 +42,7 @@ static inc_group_count(struct list_head *list, | |||
42 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM | 42 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM |
43 | %token PE_EVENT_NAME | 43 | %token PE_EVENT_NAME |
44 | %token PE_NAME | 44 | %token PE_NAME |
45 | %token PE_BPF_OBJECT | 45 | %token PE_BPF_OBJECT PE_BPF_SOURCE |
46 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 46 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
47 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT | 47 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT |
48 | %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP | 48 | %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP |
@@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list, | |||
55 | %type <num> PE_TERM | 55 | %type <num> PE_TERM |
56 | %type <str> PE_NAME | 56 | %type <str> PE_NAME |
57 | %type <str> PE_BPF_OBJECT | 57 | %type <str> PE_BPF_OBJECT |
58 | %type <str> PE_BPF_SOURCE | ||
58 | %type <str> PE_NAME_CACHE_TYPE | 59 | %type <str> PE_NAME_CACHE_TYPE |
59 | %type <str> PE_NAME_CACHE_OP_RESULT | 60 | %type <str> PE_NAME_CACHE_OP_RESULT |
60 | %type <str> PE_MODIFIER_EVENT | 61 | %type <str> PE_MODIFIER_EVENT |
@@ -461,7 +462,17 @@ PE_BPF_OBJECT | |||
461 | struct list_head *list; | 462 | struct list_head *list; |
462 | 463 | ||
463 | ALLOC_LIST(list); | 464 | ALLOC_LIST(list); |
464 | ABORT_ON(parse_events_load_bpf(data, list, $1)); | 465 | ABORT_ON(parse_events_load_bpf(data, list, $1, false)); |
466 | $$ = list; | ||
467 | } | ||
468 | | | ||
469 | PE_BPF_SOURCE | ||
470 | { | ||
471 | struct parse_events_evlist *data = _data; | ||
472 | struct list_head *list; | ||
473 | |||
474 | ALLOC_LIST(list); | ||
475 | ABORT_ON(parse_events_load_bpf(data, list, $1, true)); | ||
465 | $$ = list; | 476 | $$ = list; |
466 | } | 477 | } |
467 | 478 | ||
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index f729f9e99f99..c83832b555e5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -360,12 +360,15 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
360 | int fd = dso__data_get_fd(map->dso, ui->machine); | 360 | int fd = dso__data_get_fd(map->dso, ui->machine); |
361 | int is_exec = elf_is_exec(fd, map->dso->name); | 361 | int is_exec = elf_is_exec(fd, map->dso->name); |
362 | unw_word_t base = is_exec ? 0 : map->start; | 362 | unw_word_t base = is_exec ? 0 : map->start; |
363 | const char *symfile; | ||
363 | 364 | ||
364 | if (fd >= 0) | 365 | if (fd >= 0) |
365 | dso__data_put_fd(map->dso); | 366 | dso__data_put_fd(map->dso); |
366 | 367 | ||
368 | symfile = map->dso->symsrc_filename ?: map->dso->name; | ||
369 | |||
367 | memset(&di, 0, sizeof(di)); | 370 | memset(&di, 0, sizeof(di)); |
368 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, | 371 | if (dwarf_find_debug_frame(0, &di, ip, base, symfile, |
369 | map->start, map->end)) | 372 | map->start, map->end)) |
370 | return dwarf_search_unwind_table(as, ip, &di, pi, | 373 | return dwarf_search_unwind_table(as, ip, &di, pi, |
371 | need_unwind_info, arg); | 374 | need_unwind_info, arg); |