aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-10-14 08:41:20 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-10-29 16:16:23 -0400
commitd509db0473e40134286271b1d1adadccf42ac467 (patch)
treee9ec6d2dad1ff0465f2d68edee9e8fcf8c510a62
parent71dc2326252ff1bcdddc05db03c0f831d16c9447 (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.c44
-rw-r--r--tools/perf/util/bpf-loader.c17
-rw-r--r--tools/perf/util/bpf-loader.h5
-rw-r--r--tools/perf/util/parse-events.c5
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.l3
-rw-r--r--tools/perf/util/parse-events.y15
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
10static void *(*bpf_map_lookup_elem)(void *map, void *key) =
11 (void *) BPF_FUNC_map_lookup_elem;
12static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
13 (void *) BPF_FUNC_map_update_elem;
14
15struct 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))
23struct 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
30SEC("func=sys_epoll_pwait")
31int 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}
43char _license[] SEC("license") = "GPL";
44int _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) \
17static int libbpf_##name(const char *fmt, ...) \ 18static 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
36struct bpf_object *bpf__prepare_load(const char *filename) 37struct 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
21struct bpf_object *bpf__prepare_load(const char *filename); 21struct bpf_object *bpf__prepare_load(const char *filename, bool source);
22 22
23void bpf__clear(void); 23void 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
36static inline struct bpf_object * 36static inline struct bpf_object *
37bpf__prepare_load(const char *filename __maybe_unused) 37bpf__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
627int parse_events_load_bpf(struct parse_events_evlist *data, 627int 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);
126int parse_events_load_bpf(struct parse_events_evlist *data, 126int 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 */
130struct bpf_object; 131struct bpf_object;
131int parse_events_load_bpf_obj(struct parse_events_evlist *data, 132int 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 [^,{}/]*[{][^}]*[}][^,{}/]*
116event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* 116event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
117event [^,{}/]+ 117event [^,{}/]+
118bpf_object .*\.(o|bpf) 118bpf_object .*\.(o|bpf)
119bpf_source .*\.c
119 120
120num_dec [0-9]+ 121num_dec [0-9]+
121num_hex 0x[a-fA-F0-9]+ 122num_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|
469PE_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