[RFC PATCH v2 23/26] perf record: Add uBPF hooks at beginning and end of perf record

From: He Kuang
Date: Sun Jun 26 2016 - 07:22:42 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: He Kuang <hekuang@xxxxxxxxxx>
Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>
---
tools/perf/builtin-record.c | 4 +++
tools/perf/util/Build | 2 +-
tools/perf/util/ubpf-hooks-list.h | 34 ++++++++++++++++++++
tools/perf/util/ubpf-hooks.c | 68 +++++++++++++++++++++++++++++++++++++++
tools/perf/util/ubpf-hooks.h | 41 +++++++++++++++++++++++
5 files changed, 148 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 81411b1..c956d57 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -36,6 +36,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>
@@ -893,6 +894,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)

trigger_ready(&auxtrace_snapshot_trigger);
trigger_ready(&switch_output_trigger);
+ ubpf_hook_perf_record_start(0);
for (;;) {
unsigned long long hits = rec->samples;

@@ -957,6 +959,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
disabled = true;
}
}
+ ubpf_hook_perf_record_end(rec->samples, 0);
+
trigger_off(&auxtrace_snapshot_trigger);
trigger_off(&switch_output_trigger);

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index d12ef7d..80f3c20 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..b796334
--- /dev/null
+++ b/tools/perf/util/ubpf-hooks-list.h
@@ -0,0 +1,34 @@
+UBPF_HOOK(perf_record_start,
+ __UBPF_HOOK_PROTO(
+ __proto(int dummy)
+ ),
+
+ __UBPF_HOOK_ARGS(dummy),
+
+ __UBPF_HOOK_STRUCT__entry(
+ __field(int, dummy)
+ ),
+
+ __UBPF_HOOK_ASSIGN(
+ __entry.dummy = dummy;
+ )
+ );
+
+UBPF_HOOK(perf_record_end,
+ __UBPF_HOOK_PROTO(
+ __proto(int samples),
+ __proto(int dummy)
+ ),
+
+ __UBPF_HOOK_ARGS(samples, dummy),
+
+ __UBPF_HOOK_STRUCT__entry(
+ __field(int, samples)
+ __field(int, dummy)
+ ),
+
+ __UBPF_HOOK_ASSIGN(
+ __entry.samples = samples;
+ __entry.dummy = dummy;
+ )
+ );
diff --git a/tools/perf/util/ubpf-hooks.c b/tools/perf/util/ubpf-hooks.c
new file mode 100644
index 0000000..6ffe344
--- /dev/null
+++ b/tools/perf/util/ubpf-hooks.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016, Wang Nan <wangnan0@xxxxxxxxxx>
+ * Copyright (C) 2016, He Kuang <hekuang@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 __maybe_unused,
+ void *mem __maybe_unused, size_t len __maybe_unused)
+{
+ return 0;
+}
+
+static int
+run_ubpf_programs(const char *expect_title, void *mem, size_t len)
+{
+
+ struct bpf_object *obj, *tmp;
+ struct bpf_program *prog;
+ const char *title;
+ int err;
+
+ 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)
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#define __UBPF_HOOK_PROTO(args...) args
+#define __UBPF_HOOK_ARG(args...) args
+#define __UBPF_HOOK_STRUCT__entry(args...) args
+#define __proto(args) args
+#define __field(type, item) type item;
+
+#define UBPF_HOOK(name, proto, args, tstruct, assign) \
+ struct ubpf_hook_##name##_proto {tstruct}
+#include "ubpf-hooks-list.h"
+#undef UBPF_HOOK
+
+#define __UBPF_HOOK_ASSIGN(code...) code
+
+#define UBPF_HOOK(name, proto, args, tstruct, assign) \
+ int ubpf_hook_##name(proto) \
+ { \
+ struct ubpf_hook_##name##_proto __entry; \
+ assign; \
+ return run_ubpf_programs("UBPF;"#name, \
+ &__entry, sizeof(__entry)); \
+ }
+#include "ubpf-hooks-list.h"
+#undef UBPF_HOOK
diff --git a/tools/perf/util/ubpf-hooks.h b/tools/perf/util/ubpf-hooks.h
new file mode 100644
index 0000000..4d2f23e
--- /dev/null
+++ b/tools/perf/util/ubpf-hooks.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016, Wang Nan <wangnan0@xxxxxxxxxx>
+ * Copyright (C) 2016, He Kuang <hekuang@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
+
+#define __UBPF_HOOK_PROTO(args...) args
+#define __UBPF_HOOK_ARG(args...) args
+#define __UBPF_HOOK_STRUCT__entry(args...) args
+#define __field(type, item) type item;
+
+#ifdef HAVE_UBPF_SUPPORT
+
+#define __proto(args) args
+#define UBPF_HOOK(name, proto, args, struct, assign) int ubpf_hook_##name(proto)
+
+#include "ubpf-hooks-list.h"
+
+#else
+
+#define __proto(args) args __maybe_unused
+#define UBPF_HOOK(name, proto, args, struct, assign) \
+ static inline int ubpf_hook_##name(proto) {return 0; } \
+
+#include "ubpf-hooks-list.h"
+#endif
+
+#undef UBPF_HOOK
+#undef __UBPF_HOOK_PROTO
+#undef __UBPF_HOOK_ARG
+#undef __UBPF_HOOK_STRUCT__entry
+#undef __field
+#undef __proto
+
+#endif /* __PERF_UBPF_HOOKS_H */
--
1.8.5.2