Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Enable passing bpf object file to --event

By introducing new rules in tools/perf/util/parse-events.[ly], this
patch enables 'perf record --event bpf_file.o' to select events by an
eBPF object file. It calls parse_events_load_bpf() to load that file,
which uses bpf__prepare_load() and finally calls bpf_object__open() for
the object files.

After applying this patch, commands like:

# perf record --event foo.o sleep

become possible.

However, at this point it is unable to link any useful things onto the
evsel list because the creating of probe points and BPF program
attaching have not been implemented. Before real events are possible to
be extracted, to avoid perf report error because of empty evsel list,
this patch link a dummy evsel. The dummy event related code will be
removed when probing and extracting code is ready.

Commiter notes:

Using it:

$ ls -la foo.o
ls: cannot access foo.o: No such file or directory
$ perf record --event foo.o sleep
libbpf: failed to open foo.o: No such file or directory
event syntax error: 'foo.o'
\___ BPF object file 'foo.o' is invalid

(add -v to see detail)
Run 'perf list' for a list of valid events

Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]

-e, --event <event> event selector. use 'perf list' to list available events
$

$ file /tmp/build/perf/perf.o
/tmp/build/perf/perf.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ perf record --event /tmp/build/perf/perf.o sleep
libbpf: /tmp/build/perf/perf.o is not an eBPF object file
event syntax error: '/tmp/build/perf/perf.o'
\___ BPF object file '/tmp/build/perf/perf.o' is invalid

(add -v to see detail)
Run 'perf list' for a list of valid events

Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]

-e, --event <event> event selector. use 'perf list' to list available events
$

$ file /tmp/foo.o
/tmp/foo.o: ELF 64-bit LSB relocatable, no machine, version 1 (SYSV), not stripped
$ perf record --event /tmp/foo.o sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data ]
$ perf evlist
/tmp/foo.o
$ perf evlist -v
/tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1
$

So, type 1 is PERF_TYPE_SOFTWARE, config 0x9 is PERF_COUNT_SW_DUMMY, ok.

$ perf report --stdio
Error:
The perf.data file has no samples!
# To display the perf.data header info, please use --header/--header-only options.
#
$

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David Ahern <dsahern@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kaixu Xia <xiakaixu@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1444826502-49291-4-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
84c86ca1 69d262a9

+88 -1
+2
tools/perf/perf.c
··· 15 15 #include "util/run-command.h" 16 16 #include "util/parse-events.h" 17 17 #include "util/parse-options.h" 18 + #include "util/bpf-loader.h" 18 19 #include "util/debug.h" 19 20 #include <api/fs/tracing_path.h> 20 21 #include <pthread.h> ··· 386 385 status = p->fn(argc, argv, prefix); 387 386 exit_browser(status); 388 387 perf_env__exit(&perf_env); 388 + bpf__clear(); 389 389 390 390 if (status) 391 391 return status & 0xff;
+1
tools/perf/util/Build
··· 87 87 libperf-y += parse-branch-options.o 88 88 libperf-y += parse-regs-options.o 89 89 90 + libperf-$(CONFIG_LIBBPF) += bpf-loader.o 90 91 libperf-$(CONFIG_LIBELF) += symbol-elf.o 91 92 libperf-$(CONFIG_LIBELF) += probe-file.o 92 93 libperf-$(CONFIG_LIBELF) += probe-event.o
+57
tools/perf/util/parse-events.c
··· 11 11 #include "symbol.h" 12 12 #include "cache.h" 13 13 #include "header.h" 14 + #include "bpf-loader.h" 14 15 #include "debug.h" 15 16 #include <api/fs/tracing_path.h> 16 17 #include "parse-events-bison.h" ··· 528 527 529 528 closedir(events_dir); 530 529 return ret; 530 + } 531 + 532 + int parse_events_load_bpf_obj(struct parse_events_evlist *data, 533 + struct list_head *list, 534 + struct bpf_object *obj) 535 + { 536 + int err; 537 + char errbuf[BUFSIZ]; 538 + 539 + if (IS_ERR(obj) || !obj) { 540 + snprintf(errbuf, sizeof(errbuf), 541 + "Internal error: load bpf obj with NULL"); 542 + err = -EINVAL; 543 + goto errout; 544 + } 545 + 546 + /* 547 + * Temporary add a dummy event here so we can check whether 548 + * basic bpf loader works. Following patches will replace 549 + * dummy event by useful evsels. 550 + */ 551 + return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE, 552 + PERF_COUNT_SW_DUMMY, NULL); 553 + errout: 554 + data->error->help = strdup("(add -v to see detail)"); 555 + data->error->str = strdup(errbuf); 556 + return err; 557 + } 558 + 559 + int parse_events_load_bpf(struct parse_events_evlist *data, 560 + struct list_head *list, 561 + char *bpf_file_name) 562 + { 563 + struct bpf_object *obj; 564 + 565 + obj = bpf__prepare_load(bpf_file_name); 566 + if (IS_ERR(obj) || !obj) { 567 + char errbuf[BUFSIZ]; 568 + int err; 569 + 570 + err = obj ? PTR_ERR(obj) : -EINVAL; 571 + 572 + if (err == -ENOTSUP) 573 + snprintf(errbuf, sizeof(errbuf), 574 + "BPF support is not compiled"); 575 + else 576 + snprintf(errbuf, sizeof(errbuf), 577 + "BPF object file '%s' is invalid", 578 + bpf_file_name); 579 + 580 + data->error->help = strdup("(add -v to see detail)"); 581 + data->error->str = strdup(errbuf); 582 + return err; 583 + } 584 + 585 + return parse_events_load_bpf_obj(data, list, obj); 531 586 } 532 587 533 588 static int
+8
tools/perf/util/parse-events.h
··· 123 123 char *sys, char *event, 124 124 struct parse_events_error *error, 125 125 struct list_head *head_config); 126 + int parse_events_load_bpf(struct parse_events_evlist *data, 127 + struct list_head *list, 128 + char *bpf_file_name); 129 + /* Provide this function for perf test */ 130 + struct bpf_object; 131 + int parse_events_load_bpf_obj(struct parse_events_evlist *data, 132 + struct list_head *list, 133 + struct bpf_object *obj); 126 134 int parse_events_add_numeric(struct parse_events_evlist *data, 127 135 struct list_head *list, 128 136 u32 type, u64 config,
+3
tools/perf/util/parse-events.l
··· 115 115 group [^,{}/]*[{][^}]*[}][^,{}/]* 116 116 event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* 117 117 event [^,{}/]+ 118 + bpf_object .*\.(o|bpf) 118 119 119 120 num_dec [0-9]+ 120 121 num_hex 0x[a-fA-F0-9]+ ··· 160 159 } 161 160 162 161 {event_pmu} | 162 + {bpf_object} | 163 163 {event} { 164 164 BEGIN(INITIAL); 165 165 REWIND(1); ··· 268 266 {num_hex} { return value(yyscanner, 16); } 269 267 270 268 {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } 269 + {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } 271 270 {name} { return pmu_str_check(yyscanner); } 272 271 "/" { BEGIN(config); return '/'; } 273 272 - { return '-'; }
+17 -1
tools/perf/util/parse-events.y
··· 42 42 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM 43 43 %token PE_EVENT_NAME 44 44 %token PE_NAME 45 + %token PE_BPF_OBJECT 45 46 %token PE_MODIFIER_EVENT PE_MODIFIER_BP 46 47 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT 47 48 %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP ··· 54 53 %type <num> PE_RAW 55 54 %type <num> PE_TERM 56 55 %type <str> PE_NAME 56 + %type <str> PE_BPF_OBJECT 57 57 %type <str> PE_NAME_CACHE_TYPE 58 58 %type <str> PE_NAME_CACHE_OP_RESULT 59 59 %type <str> PE_MODIFIER_EVENT ··· 72 70 %type <tracepoint_name> tracepoint_name 73 71 %type <head> event_legacy_numeric 74 72 %type <head> event_legacy_raw 73 + %type <head> event_bpf_file 75 74 %type <head> event_def 76 75 %type <head> event_mod 77 76 %type <head> event_name ··· 206 203 event_legacy_mem | 207 204 event_legacy_tracepoint sep_dc | 208 205 event_legacy_numeric sep_dc | 209 - event_legacy_raw sep_dc 206 + event_legacy_raw sep_dc | 207 + event_bpf_file 210 208 211 209 event_pmu: 212 210 PE_NAME '/' event_config '/' ··· 450 446 451 447 ALLOC_LIST(list); 452 448 ABORT_ON(parse_events_add_numeric(data, list, PERF_TYPE_RAW, $1, NULL)); 449 + $$ = list; 450 + } 451 + 452 + event_bpf_file: 453 + PE_BPF_OBJECT 454 + { 455 + struct parse_events_evlist *data = _data; 456 + struct parse_events_error *error = data->error; 457 + struct list_head *list; 458 + 459 + ALLOC_LIST(list); 460 + ABORT_ON(parse_events_load_bpf(data, list, $1)); 453 461 $$ = list; 454 462 } 455 463