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

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>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
d509db04 71dc2326

+83 -9
+44
tools/perf/tests/bpf-script-example.c
··· 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;
+15 -2
tools/perf/util/bpf-loader.c
··· 12 12 #include "bpf-loader.h" 13 13 #include "probe-event.h" 14 14 #include "probe-finder.h" // for MAX_PROBES 15 + #include "llvm-utils.h" 15 16 16 17 #define DEFINE_PRINT_FN(name, level) \ 17 18 static int libbpf_##name(const char *fmt, ...) \ ··· 34 33 struct perf_probe_event pev; 35 34 }; 36 35 37 - struct bpf_object *bpf__prepare_load(const char *filename) 36 + struct bpf_object *bpf__prepare_load(const char *filename, bool source) 38 37 { 39 38 struct bpf_object *obj; 40 39 static bool libbpf_initialized; ··· 46 45 libbpf_initialized = true; 47 46 } 48 47 49 - obj = bpf_object__open(filename); 48 + if (source) { 49 + int err; 50 + void *obj_buf; 51 + size_t obj_buf_sz; 52 + 53 + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); 54 + if (err) 55 + return ERR_PTR(err); 56 + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); 57 + free(obj_buf); 58 + } else 59 + obj = bpf_object__open(filename); 60 + 50 61 if (!obj) { 51 62 pr_debug("bpf: failed to load %s\n", filename); 52 63 return ERR_PTR(-EINVAL);
+3 -2
tools/perf/util/bpf-loader.h
··· 18 18 int fd, void *arg); 19 19 20 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 23 void bpf__clear(void); 24 24 ··· 34 34 bpf_prog_iter_callback_t func, void *arg); 35 35 #else 36 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 40 pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); 40 41 return ERR_PTR(-ENOTSUP);
+3 -2
tools/perf/util/parse-events.c
··· 626 626 627 627 int parse_events_load_bpf(struct parse_events_evlist *data, 628 628 struct list_head *list, 629 - char *bpf_file_name) 629 + char *bpf_file_name, 630 + bool source) 630 631 { 631 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 635 if (IS_ERR(obj) || !obj) { 635 636 char errbuf[BUFSIZ]; 636 637 int err;
+2 -1
tools/perf/util/parse-events.h
··· 125 125 struct list_head *head_config); 126 126 int parse_events_load_bpf(struct parse_events_evlist *data, 127 127 struct list_head *list, 128 - char *bpf_file_name); 128 + char *bpf_file_name, 129 + bool source); 129 130 /* Provide this function for perf test */ 130 131 struct bpf_object; 131 132 int parse_events_load_bpf_obj(struct parse_events_evlist *data,
+3
tools/perf/util/parse-events.l
··· 116 116 event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* 117 117 event [^,{}/]+ 118 118 bpf_object .*\.(o|bpf) 119 + bpf_source .*\.c 119 120 120 121 num_dec [0-9]+ 121 122 num_hex 0x[a-fA-F0-9]+ ··· 162 161 163 162 {event_pmu} | 164 163 {bpf_object} | 164 + {bpf_source} | 165 165 {event} { 166 166 BEGIN(INITIAL); 167 167 REWIND(1); ··· 271 269 272 270 {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } 273 271 {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } 272 + {bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } 274 273 {name} { return pmu_str_check(yyscanner); } 275 274 "/" { BEGIN(config); return '/'; } 276 275 - { return '-'; }
+13 -2
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 + %token PE_BPF_OBJECT PE_BPF_SOURCE 46 46 %token PE_MODIFIER_EVENT PE_MODIFIER_BP 47 47 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT 48 48 %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP ··· 55 55 %type <num> PE_TERM 56 56 %type <str> PE_NAME 57 57 %type <str> PE_BPF_OBJECT 58 + %type <str> PE_BPF_SOURCE 58 59 %type <str> PE_NAME_CACHE_TYPE 59 60 %type <str> PE_NAME_CACHE_OP_RESULT 60 61 %type <str> PE_MODIFIER_EVENT ··· 462 461 struct list_head *list; 463 462 464 463 ALLOC_LIST(list); 465 - ABORT_ON(parse_events_load_bpf(data, list, $1)); 464 + ABORT_ON(parse_events_load_bpf(data, list, $1, false)); 465 + $$ = list; 466 + } 467 + | 468 + PE_BPF_SOURCE 469 + { 470 + struct parse_events_evlist *data = _data; 471 + struct list_head *list; 472 + 473 + ALLOC_LIST(list); 474 + ABORT_ON(parse_events_load_bpf(data, list, $1, true)); 466 475 $$ = list; 467 476 } 468 477