diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-10-14 08:41:20 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-10-29 16:16:23 -0400 |
commit | d509db0473e40134286271b1d1adadccf42ac467 (patch) | |
tree | e9ec6d2dad1ff0465f2d68edee9e8fcf8c510a62 | |
parent | 71dc2326252ff1bcdddc05db03c0f831d16c9447 (diff) |
perf tools: Compile scriptlets to BPF objects when passing '.c' to --event
This patch provides infrastructure for passing source files to --event
directly using:
# perf record --event bpf-file.c command
This patch does following works:
1) Allow passing '.c' file to '--event'. parse_events_load_bpf() is
expanded to allow caller tell it whether the passed file is source
file or object.
2) llvm__compile_bpf() is called to compile the '.c' file, the result
is saved into memory. Use bpf_object__open_buffer() to load the
in-memory object.
Introduces a bpf-script-example.c so we can manually test it:
# perf record --clang-opt "-DLINUX_VERSION_CODE=0x40200" --event ./bpf-script-example.c sleep 1
Note that '--clang-opt' must put before '--event'.
Futher patches will merge it into a testcase so can be tested automatically.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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-10-git-send-email-wangnan0@huawei.com
Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-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/parse-events.c | 5 | ||||
-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 |
7 files changed, 83 insertions, 9 deletions
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/parse-events.c b/tools/perf/util/parse-events.c index cee8c619ec7e..bee60583839a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -626,11 +626,12 @@ errout: | |||
626 | 626 | ||
627 | int parse_events_load_bpf(struct parse_events_evlist *data, | 627 | int parse_events_load_bpf(struct parse_events_evlist *data, |
628 | struct list_head *list, | 628 | struct list_head *list, |
629 | char *bpf_file_name) | 629 | char *bpf_file_name, |
630 | bool source) | ||
630 | { | 631 | { |
631 | struct bpf_object *obj; | 632 | struct bpf_object *obj; |
632 | 633 | ||
633 | obj = bpf__prepare_load(bpf_file_name); | 634 | obj = bpf__prepare_load(bpf_file_name, source); |
634 | if (IS_ERR(obj) || !obj) { | 635 | if (IS_ERR(obj) || !obj) { |
635 | char errbuf[BUFSIZ]; | 636 | char errbuf[BUFSIZ]; |
636 | 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 | ||