Message ID | 1444826502-49291-10-git-send-email-wangnan0@huawei.com |
---|---|
State | Accepted |
Commit | d509db0473e40134286271b1d1adadccf42ac467 |
Headers | show |
On Wed, Oct 14, 2015 at 12:41:20PM +0000, Wang Nan wrote: > 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> > Signed-off-by: He Kuang <hekuang@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: 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 > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> > Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org > --- > tools/perf/tests/bpf-script-example.c | 44 +++++++++++++++++++++++++++++++++++ > tools/perf/util/bpf-loader.c | 17 ++++++++++++-- > tools/perf/util/bpf-loader.h | 5 ++-- > tools/perf/util/parse-events.c | 5 ++-- > tools/perf/util/parse-events.h | 3 ++- > tools/perf/util/parse-events.l | 3 +++ > tools/perf/util/parse-events.y | 15 ++++++++++-- > 7 files changed, 83 insertions(+), 9 deletions(-) > create mode 100644 tools/perf/tests/bpf-script-example.c > > diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c > new file mode 100644 > index 0000000..410a70b > --- /dev/null > +++ b/tools/perf/tests/bpf-script-example.c Shouldn't it be a part of the next patch? Thanks, Namhyung > @@ -0,0 +1,44 @@ > +#ifndef LINUX_VERSION_CODE > +# error Need LINUX_VERSION_CODE > +# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' > +#endif > +#define BPF_ANY 0 > +#define BPF_MAP_TYPE_ARRAY 2 > +#define BPF_FUNC_map_lookup_elem 1 > +#define BPF_FUNC_map_update_elem 2 > + > +static void *(*bpf_map_lookup_elem)(void *map, void *key) = > + (void *) BPF_FUNC_map_lookup_elem; > +static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = > + (void *) BPF_FUNC_map_update_elem; > + > +struct bpf_map_def { > + unsigned int type; > + unsigned int key_size; > + unsigned int value_size; > + unsigned int max_entries; > +}; > + > +#define SEC(NAME) __attribute__((section(NAME), used)) > +struct bpf_map_def SEC("maps") flip_table = { > + .type = BPF_MAP_TYPE_ARRAY, > + .key_size = sizeof(int), > + .value_size = sizeof(int), > + .max_entries = 1, > +}; > + > +SEC("func=sys_epoll_pwait") > +int bpf_func__sys_epoll_pwait(void *ctx) > +{ > + int ind =0; > + int *flag = bpf_map_lookup_elem(&flip_table, &ind); > + int new_flag; > + if (!flag) > + return 0; > + /* flip flag and store back */ > + new_flag = !*flag; > + bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); > + return new_flag; > +} > +char _license[] SEC("license") = "GPL"; > +int _version SEC("version") = LINUX_VERSION_CODE; > diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c > index aa784a4..ba6f752 100644 > --- a/tools/perf/util/bpf-loader.c > +++ b/tools/perf/util/bpf-loader.c > @@ -12,6 +12,7 @@ > #include "bpf-loader.h" > #include "probe-event.h" > #include "probe-finder.h" // for MAX_PROBES > +#include "llvm-utils.h" > > #define DEFINE_PRINT_FN(name, level) \ > static int libbpf_##name(const char *fmt, ...) \ > @@ -33,7 +34,7 @@ struct bpf_prog_priv { > struct perf_probe_event pev; > }; > > -struct bpf_object *bpf__prepare_load(const char *filename) > +struct bpf_object *bpf__prepare_load(const char *filename, bool source) > { > struct bpf_object *obj; > static bool libbpf_initialized; > @@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename) > libbpf_initialized = true; > } > > - obj = bpf_object__open(filename); > + if (source) { > + int err; > + void *obj_buf; > + size_t obj_buf_sz; > + > + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); > + if (err) > + return ERR_PTR(err); > + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); > + free(obj_buf); > + } else > + obj = bpf_object__open(filename); > + > if (!obj) { > pr_debug("bpf: failed to load %s\n", filename); > return ERR_PTR(-EINVAL); > diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h > index a8f25ee..ccd8d7f 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, > int fd, void *arg); > > #ifdef HAVE_LIBBPF_SUPPORT > -struct bpf_object *bpf__prepare_load(const char *filename); > +struct bpf_object *bpf__prepare_load(const char *filename, bool source); > > void bpf__clear(void); > > @@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj, > bpf_prog_iter_callback_t func, void *arg); > #else > static inline struct bpf_object * > -bpf__prepare_load(const char *filename __maybe_unused) > +bpf__prepare_load(const char *filename __maybe_unused, > + bool source __maybe_unused) > { > pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); > return ERR_PTR(-ENOTSUP); > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c > index 5087023..4849dbd 100644 > --- a/tools/perf/util/parse-events.c > +++ b/tools/perf/util/parse-events.c > @@ -626,11 +626,12 @@ errout: > > int parse_events_load_bpf(struct parse_events_evlist *data, > struct list_head *list, > - char *bpf_file_name) > + char *bpf_file_name, > + bool source) > { > struct bpf_object *obj; > > - obj = bpf__prepare_load(bpf_file_name); > + obj = bpf__prepare_load(bpf_file_name, source); > if (IS_ERR(obj) || !obj) { > char errbuf[BUFSIZ]; > int err; > diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h > index fbb16c7..8f17c83 100644 > --- a/tools/perf/util/parse-events.h > +++ b/tools/perf/util/parse-events.h > @@ -123,7 +123,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, > struct list_head *head_config); > int parse_events_load_bpf(struct parse_events_evlist *data, > struct list_head *list, > - char *bpf_file_name); > + char *bpf_file_name, > + bool source); > /* Provide this function for perf test */ > struct bpf_object; > 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 5e5d31a..eeea4e1 100644 > --- a/tools/perf/util/parse-events.l > +++ b/tools/perf/util/parse-events.l > @@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]* > event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* > event [^,{}/]+ > bpf_object .*\.(o|bpf) > +bpf_source .*\.c > > num_dec [0-9]+ > num_hex 0x[a-fA-F0-9]+ > @@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3} > > {event_pmu} | > {bpf_object} | > +{bpf_source} | > {event} { > BEGIN(INITIAL); > REWIND(1); > @@ -267,6 +269,7 @@ r{num_raw_hex} { return raw(yyscanner); } > > {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } > {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } > +{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } > {name} { return pmu_str_check(yyscanner); } > "/" { BEGIN(config); return '/'; } > - { return '-'; } > diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y > index 497f19b..ad37996 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, > %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM > %token PE_EVENT_NAME > %token PE_NAME > -%token PE_BPF_OBJECT > +%token PE_BPF_OBJECT PE_BPF_SOURCE > %token PE_MODIFIER_EVENT PE_MODIFIER_BP > %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT > %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP > @@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list, > %type <num> PE_TERM > %type <str> PE_NAME > %type <str> PE_BPF_OBJECT > +%type <str> PE_BPF_SOURCE > %type <str> PE_NAME_CACHE_TYPE > %type <str> PE_NAME_CACHE_OP_RESULT > %type <str> PE_MODIFIER_EVENT > @@ -461,7 +462,17 @@ PE_BPF_OBJECT > struct list_head *list; > > ALLOC_LIST(list); > - ABORT_ON(parse_events_load_bpf(data, list, $1)); > + ABORT_ON(parse_events_load_bpf(data, list, $1, false)); > + $$ = list; > +} > +| > +PE_BPF_SOURCE > +{ > + struct parse_events_evlist *data = _data; > + struct list_head *list; > + > + ALLOC_LIST(list); > + ABORT_ON(parse_events_load_bpf(data, list, $1, true)); > $$ = list; > } > > -- > 1.8.3.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
On 2015/10/14 23:45, Namhyung Kim wrote: > On Wed, Oct 14, 2015 at 12:41:20PM +0000, Wang Nan wrote: >> 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> >> Signed-off-by: He Kuang <hekuang@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: 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 >> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> >> Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org >> --- >> tools/perf/tests/bpf-script-example.c | 44 +++++++++++++++++++++++++++++++++++ >> tools/perf/util/bpf-loader.c | 17 ++++++++++++-- >> tools/perf/util/bpf-loader.h | 5 ++-- >> tools/perf/util/parse-events.c | 5 ++-- >> tools/perf/util/parse-events.h | 3 ++- >> tools/perf/util/parse-events.l | 3 +++ >> tools/perf/util/parse-events.y | 15 ++++++++++-- >> 7 files changed, 83 insertions(+), 9 deletions(-) >> create mode 100644 tools/perf/tests/bpf-script-example.c >> >> diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c >> new file mode 100644 >> index 0000000..410a70b >> --- /dev/null >> +++ b/tools/perf/tests/bpf-script-example.c > Shouldn't it be a part of the next patch? I think putting the sample file in this patch should be better. In commit message I show a cmdline to utilize scriptlet compiling. If we put the sample code into next patch, then people get to this point have to write his/her own script to test scriptlet compiling manually. Thank you. > Thanks, > Namhyung > > >> @@ -0,0 +1,44 @@ >> +#ifndef LINUX_VERSION_CODE >> +# error Need LINUX_VERSION_CODE >> +# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' >> +#endif >> +#define BPF_ANY 0 >> +#define BPF_MAP_TYPE_ARRAY 2 >> +#define BPF_FUNC_map_lookup_elem 1 >> +#define BPF_FUNC_map_update_elem 2 >> + >> +static void *(*bpf_map_lookup_elem)(void *map, void *key) = >> + (void *) BPF_FUNC_map_lookup_elem; >> +static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = >> + (void *) BPF_FUNC_map_update_elem; >> + >> +struct bpf_map_def { >> + unsigned int type; >> + unsigned int key_size; >> + unsigned int value_size; >> + unsigned int max_entries; >> +}; >> + >> +#define SEC(NAME) __attribute__((section(NAME), used)) >> +struct bpf_map_def SEC("maps") flip_table = { >> + .type = BPF_MAP_TYPE_ARRAY, >> + .key_size = sizeof(int), >> + .value_size = sizeof(int), >> + .max_entries = 1, >> +}; >> + >> +SEC("func=sys_epoll_pwait") >> +int bpf_func__sys_epoll_pwait(void *ctx) >> +{ >> + int ind =0; >> + int *flag = bpf_map_lookup_elem(&flip_table, &ind); >> + int new_flag; >> + if (!flag) >> + return 0; >> + /* flip flag and store back */ >> + new_flag = !*flag; >> + bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); >> + return new_flag; >> +} >> +char _license[] SEC("license") = "GPL"; >> +int _version SEC("version") = LINUX_VERSION_CODE; >> diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c >> index aa784a4..ba6f752 100644 >> --- a/tools/perf/util/bpf-loader.c >> +++ b/tools/perf/util/bpf-loader.c >> @@ -12,6 +12,7 @@ >> #include "bpf-loader.h" >> #include "probe-event.h" >> #include "probe-finder.h" // for MAX_PROBES >> +#include "llvm-utils.h" >> >> #define DEFINE_PRINT_FN(name, level) \ >> static int libbpf_##name(const char *fmt, ...) \ >> @@ -33,7 +34,7 @@ struct bpf_prog_priv { >> struct perf_probe_event pev; >> }; >> >> -struct bpf_object *bpf__prepare_load(const char *filename) >> +struct bpf_object *bpf__prepare_load(const char *filename, bool source) >> { >> struct bpf_object *obj; >> static bool libbpf_initialized; >> @@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename) >> libbpf_initialized = true; >> } >> >> - obj = bpf_object__open(filename); >> + if (source) { >> + int err; >> + void *obj_buf; >> + size_t obj_buf_sz; >> + >> + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); >> + if (err) >> + return ERR_PTR(err); >> + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); >> + free(obj_buf); >> + } else >> + obj = bpf_object__open(filename); >> + >> if (!obj) { >> pr_debug("bpf: failed to load %s\n", filename); >> return ERR_PTR(-EINVAL); >> diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h >> index a8f25ee..ccd8d7f 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, >> int fd, void *arg); >> >> #ifdef HAVE_LIBBPF_SUPPORT >> -struct bpf_object *bpf__prepare_load(const char *filename); >> +struct bpf_object *bpf__prepare_load(const char *filename, bool source); >> >> void bpf__clear(void); >> >> @@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj, >> bpf_prog_iter_callback_t func, void *arg); >> #else >> static inline struct bpf_object * >> -bpf__prepare_load(const char *filename __maybe_unused) >> +bpf__prepare_load(const char *filename __maybe_unused, >> + bool source __maybe_unused) >> { >> pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); >> return ERR_PTR(-ENOTSUP); >> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c >> index 5087023..4849dbd 100644 >> --- a/tools/perf/util/parse-events.c >> +++ b/tools/perf/util/parse-events.c >> @@ -626,11 +626,12 @@ errout: >> >> int parse_events_load_bpf(struct parse_events_evlist *data, >> struct list_head *list, >> - char *bpf_file_name) >> + char *bpf_file_name, >> + bool source) >> { >> struct bpf_object *obj; >> >> - obj = bpf__prepare_load(bpf_file_name); >> + obj = bpf__prepare_load(bpf_file_name, source); >> if (IS_ERR(obj) || !obj) { >> char errbuf[BUFSIZ]; >> int err; >> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h >> index fbb16c7..8f17c83 100644 >> --- a/tools/perf/util/parse-events.h >> +++ b/tools/perf/util/parse-events.h >> @@ -123,7 +123,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, >> struct list_head *head_config); >> int parse_events_load_bpf(struct parse_events_evlist *data, >> struct list_head *list, >> - char *bpf_file_name); >> + char *bpf_file_name, >> + bool source); >> /* Provide this function for perf test */ >> struct bpf_object; >> 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 5e5d31a..eeea4e1 100644 >> --- a/tools/perf/util/parse-events.l >> +++ b/tools/perf/util/parse-events.l >> @@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]* >> event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* >> event [^,{}/]+ >> bpf_object .*\.(o|bpf) >> +bpf_source .*\.c >> >> num_dec [0-9]+ >> num_hex 0x[a-fA-F0-9]+ >> @@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3} >> >> {event_pmu} | >> {bpf_object} | >> +{bpf_source} | >> {event} { >> BEGIN(INITIAL); >> REWIND(1); >> @@ -267,6 +269,7 @@ r{num_raw_hex} { return raw(yyscanner); } >> >> {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } >> {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } >> +{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } >> {name} { return pmu_str_check(yyscanner); } >> "/" { BEGIN(config); return '/'; } >> - { return '-'; } >> diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y >> index 497f19b..ad37996 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, >> %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM >> %token PE_EVENT_NAME >> %token PE_NAME >> -%token PE_BPF_OBJECT >> +%token PE_BPF_OBJECT PE_BPF_SOURCE >> %token PE_MODIFIER_EVENT PE_MODIFIER_BP >> %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT >> %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP >> @@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list, >> %type <num> PE_TERM >> %type <str> PE_NAME >> %type <str> PE_BPF_OBJECT >> +%type <str> PE_BPF_SOURCE >> %type <str> PE_NAME_CACHE_TYPE >> %type <str> PE_NAME_CACHE_OP_RESULT >> %type <str> PE_MODIFIER_EVENT >> @@ -461,7 +462,17 @@ PE_BPF_OBJECT >> struct list_head *list; >> >> ALLOC_LIST(list); >> - ABORT_ON(parse_events_load_bpf(data, list, $1)); >> + ABORT_ON(parse_events_load_bpf(data, list, $1, false)); >> + $$ = list; >> +} >> +| >> +PE_BPF_SOURCE >> +{ >> + struct parse_events_evlist *data = _data; >> + struct list_head *list; >> + >> + ALLOC_LIST(list); >> + ABORT_ON(parse_events_load_bpf(data, list, $1, true)); >> $$ = list; >> } >> >> -- >> 1.8.3.4 >> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c new file mode 100644 index 0000000..410a70b --- /dev/null +++ b/tools/perf/tests/bpf-script-example.c @@ -0,0 +1,44 @@ +#ifndef LINUX_VERSION_CODE +# error Need LINUX_VERSION_CODE +# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' +#endif +#define BPF_ANY 0 +#define BPF_MAP_TYPE_ARRAY 2 +#define BPF_FUNC_map_lookup_elem 1 +#define BPF_FUNC_map_update_elem 2 + +static void *(*bpf_map_lookup_elem)(void *map, void *key) = + (void *) BPF_FUNC_map_lookup_elem; +static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = + (void *) BPF_FUNC_map_update_elem; + +struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; +}; + +#define SEC(NAME) __attribute__((section(NAME), used)) +struct bpf_map_def SEC("maps") flip_table = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1, +}; + +SEC("func=sys_epoll_pwait") +int bpf_func__sys_epoll_pwait(void *ctx) +{ + int ind =0; + int *flag = bpf_map_lookup_elem(&flip_table, &ind); + int new_flag; + if (!flag) + return 0; + /* flip flag and store back */ + new_flag = !*flag; + bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); + return new_flag; +} +char _license[] SEC("license") = "GPL"; +int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index aa784a4..ba6f752 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -12,6 +12,7 @@ #include "bpf-loader.h" #include "probe-event.h" #include "probe-finder.h" // for MAX_PROBES +#include "llvm-utils.h" #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ @@ -33,7 +34,7 @@ struct bpf_prog_priv { struct perf_probe_event pev; }; -struct bpf_object *bpf__prepare_load(const char *filename) +struct bpf_object *bpf__prepare_load(const char *filename, bool source) { struct bpf_object *obj; static bool libbpf_initialized; @@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename) libbpf_initialized = true; } - obj = bpf_object__open(filename); + if (source) { + int err; + void *obj_buf; + size_t obj_buf_sz; + + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); + if (err) + return ERR_PTR(err); + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); + free(obj_buf); + } else + obj = bpf_object__open(filename); + if (!obj) { pr_debug("bpf: failed to load %s\n", filename); return ERR_PTR(-EINVAL); diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index a8f25ee..ccd8d7f 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, int fd, void *arg); #ifdef HAVE_LIBBPF_SUPPORT -struct bpf_object *bpf__prepare_load(const char *filename); +struct bpf_object *bpf__prepare_load(const char *filename, bool source); void bpf__clear(void); @@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj, bpf_prog_iter_callback_t func, void *arg); #else static inline struct bpf_object * -bpf__prepare_load(const char *filename __maybe_unused) +bpf__prepare_load(const char *filename __maybe_unused, + bool source __maybe_unused) { pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); return ERR_PTR(-ENOTSUP); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5087023..4849dbd 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -626,11 +626,12 @@ errout: int parse_events_load_bpf(struct parse_events_evlist *data, struct list_head *list, - char *bpf_file_name) + char *bpf_file_name, + bool source) { struct bpf_object *obj; - obj = bpf__prepare_load(bpf_file_name); + obj = bpf__prepare_load(bpf_file_name, source); if (IS_ERR(obj) || !obj) { char errbuf[BUFSIZ]; int err; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index fbb16c7..8f17c83 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -123,7 +123,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, struct list_head *head_config); int parse_events_load_bpf(struct parse_events_evlist *data, struct list_head *list, - char *bpf_file_name); + char *bpf_file_name, + bool source); /* Provide this function for perf test */ struct bpf_object; 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 5e5d31a..eeea4e1 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ bpf_object .*\.(o|bpf) +bpf_source .*\.c num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ @@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3} {event_pmu} | {bpf_object} | +{bpf_source} | {event} { BEGIN(INITIAL); REWIND(1); @@ -267,6 +269,7 @@ r{num_raw_hex} { return raw(yyscanner); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } +{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } {name} { return pmu_str_check(yyscanner); } "/" { BEGIN(config); return '/'; } - { return '-'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 497f19b..ad37996 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, %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM %token PE_EVENT_NAME %token PE_NAME -%token PE_BPF_OBJECT +%token PE_BPF_OBJECT PE_BPF_SOURCE %token PE_MODIFIER_EVENT PE_MODIFIER_BP %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP @@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list, %type <num> PE_TERM %type <str> PE_NAME %type <str> PE_BPF_OBJECT +%type <str> PE_BPF_SOURCE %type <str> PE_NAME_CACHE_TYPE %type <str> PE_NAME_CACHE_OP_RESULT %type <str> PE_MODIFIER_EVENT @@ -461,7 +462,17 @@ PE_BPF_OBJECT struct list_head *list; ALLOC_LIST(list); - ABORT_ON(parse_events_load_bpf(data, list, $1)); + ABORT_ON(parse_events_load_bpf(data, list, $1, false)); + $$ = list; +} +| +PE_BPF_SOURCE +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_load_bpf(data, list, $1, true)); $$ = list; }