[RFC PATCH 12/13] perf record: Add UBPF hooks at beginning and end of perf record

From: Wang Nan
Date: Wed Apr 20 2016 - 14:02:56 EST


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 <wangnan0@xxxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Alexei Starovoitov <ast@xxxxxxxxxx>
Cc: Brendan Gregg <brendan.d.gregg@xxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Li Zefan <lizefan@xxxxxxxxxx>
---
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 <wangnan0@xxxxxxxxxx>
+ * 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 <wangnan0@xxxxxxxxxx>
+ * 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