Like tracepoint in kernel code, UBPF hooks can be added in perf code and trigger UBPF programs passed by BPF scripts. The first two UBPF hooks added are record start/end. UBPF scripts can initial BPF maps in record start, and report result when record finished.
Signed-off-by: Wang Nan <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Brendan Gregg <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Li Zefan <[email protected]> --- tools/perf/builtin-record.c | 4 ++ tools/perf/util/Build | 2 +- tools/perf/util/ubpf-hooks-list.h | 10 +++++ tools/perf/util/ubpf-hooks.c | 81 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/ubpf-hooks.h | 35 +++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/ubpf-hooks-list.h create mode 100644 tools/perf/util/ubpf-hooks.c create mode 100644 tools/perf/util/ubpf-hooks.h diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c7f92cc..0c49249 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,6 +35,7 @@ #include "util/llvm-utils.h" #include "util/bpf-loader.h" #include "util/trigger.h" +#include "util/ubpf-hooks.h" #include "asm/bug.h" #include <unistd.h> @@ -824,6 +825,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) auxtrace_snapshot_ready(); switch_output_ready(); + ubpf_hook_perf_record_start(0); for (;;) { unsigned long long hits = rec->samples; @@ -888,6 +890,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) disabled = true; } } + ubpf_hook_perf_record_end(0, rec->samples); + auxtrace_snapshot_off(); switch_output_off(); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index e193e6b..c3b8763 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -87,7 +87,7 @@ libperf-y += mem-events.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o -libperf-$(CONFIG_UBPF) += ubpf-helpers.o +libperf-$(CONFIG_UBPF) += ubpf-helpers.o ubpf-hooks.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o diff --git a/tools/perf/util/ubpf-hooks-list.h b/tools/perf/util/ubpf-hooks-list.h new file mode 100644 index 0000000..626d18a --- /dev/null +++ b/tools/perf/util/ubpf-hooks-list.h @@ -0,0 +1,10 @@ +UBPF_HOOK(perf_record_start,,) + +UBPF_HOOK(perf_record_end, + __UBPF_HOOK_ARG( + __arg(int, samples) + ), + __UBPF_HOOK_ASSIGN( + __entry.samples = samples; + ) + ) diff --git a/tools/perf/util/ubpf-hooks.c b/tools/perf/util/ubpf-hooks.c new file mode 100644 index 0000000..9a53f7c --- /dev/null +++ b/tools/perf/util/ubpf-hooks.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016, Wang Nan <[email protected]> + * Copyright (C) 2016, Huawei Inc. + */ + +#include <bpf/libbpf.h> +#include <asm/bug.h> +#include <ubpf.h> +#include "ubpf-hooks.h" +#include "debug.h" + +static int run_ubpf_program(struct bpf_program *prog, void *mem, size_t len) +{ + struct ubpf_vm *vm; + int ret; + + vm = bpf_program__vm(prog); + if (!vm) { + WARN_ONCE(!vm, "Unable to fetch vm from UBPF program\n"); + return -EINVAL; + } + + ret = ubpf_exec(vm, mem, len); + pr_debug("program %s returns %d\n", + bpf_program__title(prog, false), ret); + return ret; +} + +static int +run_ubpf_programs(unsigned long flags, const char *expect_title, + void *mem, size_t len) +{ + + struct bpf_object *obj, *tmp; + struct bpf_program *prog; + const char *title; + int err; + + if (!len) + mem = NULL; + + bpf_object__for_each_safe(obj, tmp) { + bpf_object__for_each_program(prog, obj) { + if (bpf_program__is_ubpf(prog)) { + title = bpf_program__title(prog, false); + if (!title) + continue; + if (strcmp(title, expect_title) != 0) + continue; + err = run_ubpf_program(prog, mem, len); + if (err && (flags & UBPF_HOOK_BREAKABLE)) + return err; + } + } + } + + return 0; +} + +#define __arg(t, n) t n; +#define __UBPF_HOOK_ARG(args) args +#define UBPF_HOOK(n, args, assign) struct ubpf_hook_##n##_proto {args}; +#include "ubpf-hooks-list.h" +#undef UBPF_HOOK +#undef __UBPF_HOOK_ARG +#undef __arg + +#define __arg(t, n) , t n +#define __UBPF_HOOK_ASSIGN(code) do {code;} while(0) +#define __UBPF_HOOK_ARG(args) args +#define UBPF_HOOK(n, a, assign) \ +int ubpf_hook_##n(unsigned long flags a) { \ + struct ubpf_hook_##n##_proto __entry; \ + assign; \ + return run_ubpf_programs(flags, "UBPF;"#n, &__entry, sizeof(__entry));\ +} +#include "ubpf-hooks-list.h" +#undef UBPF_HOOK +#undef __UBPF_HOOK_ARG +#undef __UBPF_HOOK_ASSIGN +#undef __arg diff --git a/tools/perf/util/ubpf-hooks.h b/tools/perf/util/ubpf-hooks.h new file mode 100644 index 0000000..165f52d --- /dev/null +++ b/tools/perf/util/ubpf-hooks.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016, Wang Nan <[email protected]> + * Copyright (C) 2016, Huawei Inc. + */ +#ifndef __PERF_UBPF_HOOKS_H +#define __PERF_UBPF_HOOKS_H + +#include <linux/compiler.h> + +#define UBPF_HOOK_BREAKABLE 1 + +#ifdef HAVE_UBPF_SUPPORT + +#define __arg(t, n) , t n +#define __UBPF_HOOK_ARG(args) args +#define UBPF_HOOK(n, args, assign) int ubpf_hook_##n(unsigned long flags args); +#include "ubpf-hooks-list.h" +#undef UBPF_HOOK +#undef __UBPF_HOOK_ARG +#undef __arg + +#else + +#define __arg(t, n) , t n __maybe_unused +#define __UBPF_HOOK_ARG(args) args +#define UBPF_HOOK(n, args, assign) \ +static inline int ubpf_hook_##n(unsigned long flags __maybe_unused args) {return 0;}; +#include "ubpf-hooks-list.h" +#undef UBPF_HOOK +#undef __UBPF_HOOK_ARG +#undef __arg + +#endif + +#endif -- 1.8.3.4

