Message ID | 20161126070354.141764-26-wangnan0@huawei.com |
---|---|
State | Superseded |
Headers | show |
On Sat, Nov 26, 2016 at 07:03:49AM +0000, Wang Nan wrote: > Newly introduced jit-helpers.[ch] defines a series of helpers which helps > jitted perf hook functions accessing BPF maps defined in their BPF scripts. > The helpers fetches fd of 'struct bpf_map' from 'struct bpf_object' and the > address of 'struct bpf_map_def' in jitted file. 'struct bpf_object' is the > context passed to hooks. > > Jit helpers added in this commits are all leading with 'perf_'. We don't use > 'bpf_' prefix because in following commits 'bpf_' prefix is going to be assigned > to kernel side BPF map operations. Same operation has different protocol for > kernel and user. > > Example: > > $ cat ./test.c > /*******************************************************/ > #define SEC(name) __attribute__((section(name), used)) > #define BPF_MAP_TYPE_ARRAY 2 > #define BPF_MAP_TYPE_PERF_EVENT_ARRAY 4 > #define BPF_FUNC_map_lookup_elem 1 > static void *(*bpf_map_lookup_elem)(void *map, void *key) = > (void *) BPF_FUNC_map_lookup_elem; > struct bpf_map_def { > unsigned int type; > unsigned int key_size; > unsigned int value_size; > unsigned int max_entries; > }; > struct bpf_map_def SEC("maps") counter = { > .type = BPF_MAP_TYPE_ARRAY, > .key_size = sizeof(int), > .value_size = sizeof(int), > .max_entries = 1, > }; > extern int perf_map_update_elem(void *ctx, struct bpf_map_def *map, > void *key, void *value, unsigned long flags); > extern int perf_map_lookup_elem(void *ctx, struct bpf_map_def *map, > void *key, void *value); > SEC("sys_close=SyS_close") > int sys_close(void *ctx) > { > int key = 0; > int *value; > value = bpf_map_lookup_elem(&counter, &key); > if (!value) > return 0; > __sync_fetch_and_add(value, 1); > return 0; > } > extern int printf(const char *fmt, ...); > SEC("perfhook:record_start") > void record_start(void *ctx) > { > int key = 0; > int value = 100000000; > printf("Welcom to perf record\n"); > perf_map_update_elem(ctx, &counter, &key, &value, 0); > } > > SEC("perfhook:record_end") > void record_end(void *ctx) > { > int key = 0; > int value; > perf_map_lookup_elem(ctx, &counter, &key, &value); > printf("Goodbye, perf record, value=%d\n", value); > } > char _license[] SEC("license") = "GPL"; > int _version SEC("version") = LINUX_VERSION_CODE; > /*******************************************************/ > $ sudo perf record -e ./test.c echo Hehe > Welcom to perf record > Hehe > [ perf record: Woken up 1 times to write data ] > Goodbye, perf record, value=100000644 > [ perf record: Captured and wrote 0.014 MB perf.data ] > > Signed-off-by: Wang Nan <wangnan0@huawei.com> ... > +#define __stringify_1(x) #x > +#define __stringify(x) __stringify_1(x) > static std::map<const std::string, const void *> exported_funcs = > { > -#define EXPORT(f) {#f, (const void *)&f} > +#define EXPORT(f) {__stringify(f), (const void *)&f} > EXPORT(test__clang_callback), > EXPORT(printf), > EXPORT(puts), > + EXPORT(JIT_HELPER_FUNC_NAME(map_update_elem)), > + EXPORT(JIT_HELPER_FUNC_NAME(map_lookup_elem)), > + EXPORT(JIT_HELPER_FUNC_NAME(map_get_next_key)), > + EXPORT(JIT_HELPER_FUNC_NAME(map_pin)), > #undef EXPORT ... > +#define PARAMS(args...) args > +#define DEFINE_JIT_BPF_MAP_HELPER(name, proto, args) \ > + JIT_BPF_MAP_HELPER(name, proto) { \ > + int map_fd = get_bpf_map_fd(ctx, map); \ > + \ > + if (map_fd < 0) \ > + return map_fd; \ > + return bpf_map_##name(map_fd, args); \ > + } > + > +DEFINE_JIT_BPF_MAP_HELPER(update_elem, > + PARAMS(void *key, void *value, u64 flags), > + PARAMS(key, value, flags)) the naming and approach to exports look good to me. Acked-by: Alexei Starovoitov <ast@kernel.org>
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 743a889..33773cb 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -124,6 +124,7 @@ libperf-$(CONFIG_DWARF) += genelf_debug.o endif libperf-y += perf-hooks.o +libperf-y += jit-helpers.o libperf-$(CONFIG_CXX) += c++/ diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index f8ea9bd..48bd3ee 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -38,6 +38,7 @@ #include "llvm-utils.h" #include "util-cxx.h" #include "perf-hooks.h" +#include "jit-helpers.h" namespace perf { @@ -196,12 +197,18 @@ PerfModule::toBPFObject(void) return std::move(Buffer); } +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) static std::map<const std::string, const void *> exported_funcs = { -#define EXPORT(f) {#f, (const void *)&f} +#define EXPORT(f) {__stringify(f), (const void *)&f} EXPORT(test__clang_callback), EXPORT(printf), EXPORT(puts), + EXPORT(JIT_HELPER_FUNC_NAME(map_update_elem)), + EXPORT(JIT_HELPER_FUNC_NAME(map_lookup_elem)), + EXPORT(JIT_HELPER_FUNC_NAME(map_get_next_key)), + EXPORT(JIT_HELPER_FUNC_NAME(map_pin)), #undef EXPORT }; diff --git a/tools/perf/util/jit-helpers.c b/tools/perf/util/jit-helpers.c new file mode 100644 index 0000000..1a37a20 --- /dev/null +++ b/tools/perf/util/jit-helpers.c @@ -0,0 +1,57 @@ +/* + * jit-helper.c + * + * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com> + * Copyright (C) 2016 Huawei Inc. + * + * Provide helpers which can be invoked by jit scripts attached to + * perf hooks. + */ + +#include <util/jit-helpers.h> +#include <util/bpf-loader.h> +#include <bpf/libbpf.h> +#include <bpf/bpf.h> + +#include "asm/bug.h" + +static int get_bpf_map_fd(struct bpf_object *obj, void *map) +{ + int fd; + char errbuf[BUFSIZ]; + + fd = bpf__map_fd(obj, map); + if (fd < 0) { + bpf__strerror_map_fd(obj, map, fd, errbuf, sizeof(errbuf)); + WARN_ONCE(fd < 0, "Failed to get map fd: %s\n", errbuf); + } + return fd; +} + +#define PARAMS(args...) args +#define DEFINE_JIT_BPF_MAP_HELPER(name, proto, args) \ + JIT_BPF_MAP_HELPER(name, proto) { \ + int map_fd = get_bpf_map_fd(ctx, map); \ + \ + if (map_fd < 0) \ + return map_fd; \ + return bpf_map_##name(map_fd, args); \ + } + +DEFINE_JIT_BPF_MAP_HELPER(update_elem, + PARAMS(void *key, void *value, u64 flags), + PARAMS(key, value, flags)) + +DEFINE_JIT_BPF_MAP_HELPER(lookup_elem, + PARAMS(void *key, void *value), + PARAMS(key, value)) + +DEFINE_JIT_BPF_MAP_HELPER(get_next_key, + PARAMS(void *key, void *next_key), + PARAMS(key, next_key)) + +#define bpf_map_pin bpf_obj_pin +DEFINE_JIT_BPF_MAP_HELPER(pin, + PARAMS(const char *pathname), + PARAMS(pathname)); +#undef bpf_map_pin diff --git a/tools/perf/util/jit-helpers.h b/tools/perf/util/jit-helpers.h new file mode 100644 index 0000000..b1f7479 --- /dev/null +++ b/tools/perf/util/jit-helpers.h @@ -0,0 +1,28 @@ +#ifndef JIT_HELPERS_H +#define JIT_HELPERS_H + +#include <stdint.h> +#include <util/perf-hooks.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define JIT_HELPER_FUNC_NAME(name) perf_##name + +#define JIT_HELPER(type, name, ...) \ +type JIT_HELPER_FUNC_NAME(name)(__VA_ARGS__) + +#define JIT_BPF_MAP_HELPER(name, ...) \ + JIT_HELPER(int, map_##name, void *ctx, void *map, ##__VA_ARGS__) + +extern JIT_BPF_MAP_HELPER(update_elem, void *key, void *value, uint64_t flags); +extern JIT_BPF_MAP_HELPER(lookup_elem, void *key, void *value); +extern JIT_BPF_MAP_HELPER(get_next_key, void *key, void *next_key); +extern JIT_BPF_MAP_HELPER(pin, const char *pathname); + +#ifdef __cplusplus +} +#endif + +#endif
Newly introduced jit-helpers.[ch] defines a series of helpers which helps jitted perf hook functions accessing BPF maps defined in their BPF scripts. The helpers fetches fd of 'struct bpf_map' from 'struct bpf_object' and the address of 'struct bpf_map_def' in jitted file. 'struct bpf_object' is the context passed to hooks. Jit helpers added in this commits are all leading with 'perf_'. We don't use 'bpf_' prefix because in following commits 'bpf_' prefix is going to be assigned to kernel side BPF map operations. Same operation has different protocol for kernel and user. Example: $ cat ./test.c /*******************************************************/ #define SEC(name) __attribute__((section(name), used)) #define BPF_MAP_TYPE_ARRAY 2 #define BPF_MAP_TYPE_PERF_EVENT_ARRAY 4 #define BPF_FUNC_map_lookup_elem 1 static void *(*bpf_map_lookup_elem)(void *map, void *key) = (void *) BPF_FUNC_map_lookup_elem; struct bpf_map_def { unsigned int type; unsigned int key_size; unsigned int value_size; unsigned int max_entries; }; struct bpf_map_def SEC("maps") counter = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), .value_size = sizeof(int), .max_entries = 1, }; extern int perf_map_update_elem(void *ctx, struct bpf_map_def *map, void *key, void *value, unsigned long flags); extern int perf_map_lookup_elem(void *ctx, struct bpf_map_def *map, void *key, void *value); SEC("sys_close=SyS_close") int sys_close(void *ctx) { int key = 0; int *value; value = bpf_map_lookup_elem(&counter, &key); if (!value) return 0; __sync_fetch_and_add(value, 1); return 0; } extern int printf(const char *fmt, ...); SEC("perfhook:record_start") void record_start(void *ctx) { int key = 0; int value = 100000000; printf("Welcom to perf record\n"); perf_map_update_elem(ctx, &counter, &key, &value, 0); } SEC("perfhook:record_end") void record_end(void *ctx) { int key = 0; int value; perf_map_lookup_elem(ctx, &counter, &key, &value); printf("Goodbye, perf record, value=%d\n", value); } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /*******************************************************/ $ sudo perf record -e ./test.c echo Hehe Welcom to perf record Hehe [ perf record: Woken up 1 times to write data ] Goodbye, perf record, value=100000644 [ perf record: Captured and wrote 0.014 MB perf.data ] Signed-off-by: Wang Nan <wangnan0@huawei.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com --- tools/perf/util/Build | 1 + tools/perf/util/c++/clang.cpp | 9 ++++++- tools/perf/util/jit-helpers.c | 57 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/jit-helpers.h | 28 +++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/jit-helpers.c create mode 100644 tools/perf/util/jit-helpers.h -- 2.10.1