linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GIT PULL 00/22] perf tools: filtering events using eBPF programs
@ 2015-09-23 11:22 Wang Nan
  2015-09-23 11:22 ` [PATCH 01/22] perf ebpf: Add the libbpf glue Wang Nan
                   ` (22 more replies)
  0 siblings, 23 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme; +Cc: linux-kernel, pi3orama, Wang Nan

Hi Arnaldo,

   I hope you would be satisified with this weeks pull request. In this
patchset, we totally get rid of dummy events by utilizing Namhyung's newest
perf probing API.

Patch 1-6 are different from previous patchset. Plase have a look.

Due to some reason I can't access my kernel.org account in my company today,
so I reuse my github repository. I'll update my kernel.org tree at home.

I'll have a long vacation from Sept. 24. I hope I can discuss with you with
my private email. However, It seems impossible to modify code and test until
Oct. 7. If you find some small problem, could you please help me fix them?

Thank you.

The following changes since commit 5933944f697c15d6f1fb16dc22c02aac9d2ec206:

  perf tools: Make perf depend on libbpf (2015-09-22 10:17:01 -0300)

are available in the git repository at:

  https://github.com/WangNan0/linux.git tags/perf-ebpf-for-acme-20150923

for you to fetch changes up to 1465cf7b201b8b21c61fa54ffe15094f66e73ab0:

  perf probe: Fix module probing with shortname (2015-09-23 10:44:58 +0000)

----------------------------------------------------------------
Get rid of dummy events by utilizing new perf probe API.

Signed-off-by: Wang Nan <wangnan0@huawei.com>

----------------------------------------------------------------
He Kuang (2):
      perf tools: Add prologue for BPF programs for fetching arguments
      perf record: Support custom vmlinux path

Wang Nan (20):
      perf ebpf: Add the libbpf glue
      perf tools: Enable passing bpf object file to --event
      perf record, bpf: Create probe points for BPF programs
      perf record: Load eBPF object into kernel
      perf tools: Collect perf_evsel in BPF object files
      perf tools: Attach eBPF program to perf event
      perf record: Add clang options for compiling BPF scripts
      perf tools: Compile scriptlets to BPF objects when passing '.c' to --event
      perf test: Enforce LLVM test for BPF test
      perf test: Add 'perf test BPF'
      perf probe: Reset args and nargs for probe_trace_event when failure
      bpf tools: Load a program with different instances using preprocessor
      perf tools: Add BPF_PROLOGUE config options for further patches
      perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on
      perf tools: Generate prologue for BPF programs
      perf tools: Use same BPF program if arguments are identical
      perf tools: Allow BPF program attach to uprobe events
      perf test: Enforce LLVM test, add kbuild test
      perf test: Test BPF prologue
      perf probe: Fix module probing with shortname

 tools/lib/bpf/libbpf.c                      | 143 +++++-
 tools/lib/bpf/libbpf.h                      |  22 +
 tools/perf/arch/x86/util/Build              |   1 +
 tools/perf/builtin-record.c                 |  11 +
 tools/perf/config/Makefile                  |  12 +
 tools/perf/perf.c                           |   2 +
 tools/perf/tests/Build                      |  24 +-
 tools/perf/tests/bpf-script-example.c       |  48 ++
 tools/perf/tests/bpf-script-test-kbuild.c   |  21 +
 tools/perf/tests/bpf-script-test-prologue.c |  35 ++
 tools/perf/tests/bpf.c                      | 227 ++++++++++
 tools/perf/tests/builtin-test.c             |  12 +
 tools/perf/tests/llvm.c                     | 210 ++++++++-
 tools/perf/tests/llvm.h                     |  29 ++
 tools/perf/tests/tests.h                    |   3 +
 tools/perf/util/Build                       |   2 +
 tools/perf/util/bpf-loader.c                | 676 ++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h                |  95 ++++
 tools/perf/util/bpf-prologue.c              | 443 ++++++++++++++++++
 tools/perf/util/bpf-prologue.h              |  34 ++
 tools/perf/util/evsel.c                     |  17 +
 tools/perf/util/evsel.h                     |   1 +
 tools/perf/util/parse-events.c              | 115 +++++
 tools/perf/util/parse-events.h              |   9 +
 tools/perf/util/parse-events.l              |   6 +
 tools/perf/util/parse-events.y              |  29 +-
 tools/perf/util/probe-event.c               |   2 +-
 tools/perf/util/probe-finder.c              |   4 +
 28 files changed, 2202 insertions(+), 31 deletions(-)
 create mode 100644 tools/perf/tests/bpf-script-example.c
 create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c
 create mode 100644 tools/perf/tests/bpf-script-test-prologue.c
 create mode 100644 tools/perf/tests/bpf.c
 create mode 100644 tools/perf/tests/llvm.h
 create mode 100644 tools/perf/util/bpf-loader.c
 create mode 100644 tools/perf/util/bpf-loader.h
 create mode 100644 tools/perf/util/bpf-prologue.c
 create mode 100644 tools/perf/util/bpf-prologue.h
-- 
1.8.3.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 01/22] perf ebpf: Add the libbpf glue
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 02/22] perf tools: Enable passing bpf object file to --event Wang Nan
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Brendan Gregg, Daniel Borkmann,
	David Ahern, He Kuang, Jiri Olsa, Kaixu Xia, Masami Hiramatsu,
	Namhyung Kim, Paul Mackerras, Peter Zijlstra, Zefan Li

The 'bpf-loader.[ch]' files are introduced in this patch. Which will be
the interface between perf and libbpf. bpf__prepare_load() resides in
bpf-loader.c. Following patches will enrich these two files.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c | 57 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h | 29 ++++++++++++++++++++++
 2 files changed, 86 insertions(+)
 create mode 100644 tools/perf/util/bpf-loader.c
 create mode 100644 tools/perf/util/bpf-loader.h

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
new file mode 100644
index 0000000..ab56073
--- /dev/null
+++ b/tools/perf/util/bpf-loader.c
@@ -0,0 +1,57 @@
+/*
+ * bpf-loader.c
+ *
+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015 Huawei Inc.
+ */
+
+#include <bpf/libbpf.h>
+#include <linux/err.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-loader.h"
+
+#define DEFINE_PRINT_FN(name, level) \
+static int libbpf_##name(const char *fmt, ...)	\
+{						\
+	va_list args;				\
+	int ret;				\
+						\
+	va_start(args, fmt);			\
+	ret = veprintf(level, verbose, pr_fmt(fmt), args);\
+	va_end(args);				\
+	return ret;				\
+}
+
+DEFINE_PRINT_FN(warning, 0)
+DEFINE_PRINT_FN(info, 0)
+DEFINE_PRINT_FN(debug, 1)
+
+struct bpf_object *bpf__prepare_load(const char *filename)
+{
+	struct bpf_object *obj;
+	static bool libbpf_initialized;
+
+	if (!libbpf_initialized) {
+		libbpf_set_print(libbpf_warning,
+				 libbpf_info,
+				 libbpf_debug);
+		libbpf_initialized = true;
+	}
+
+	obj = bpf_object__open(filename);
+	if (!obj) {
+		pr_debug("bpf: failed to load %s\n", filename);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return obj;
+}
+
+void bpf__clear(void)
+{
+	struct bpf_object *obj, *tmp;
+
+	bpf_object__for_each_safe(obj, tmp)
+		bpf_object__close(obj);
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
new file mode 100644
index 0000000..f402d7c
--- /dev/null
+++ b/tools/perf/util/bpf-loader.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ */
+#ifndef __BPF_LOADER_H
+#define __BPF_LOADER_H
+
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <string.h>
+#include "debug.h"
+
+struct bpf_object;
+
+#ifdef HAVE_LIBBPF_SUPPORT
+struct bpf_object *bpf__prepare_load(const char *filename);
+
+void bpf__clear(void);
+#else
+static inline struct bpf_object *
+bpf__prepare_load(const char *filename __maybe_unused)
+{
+	pr_debug("ERROR: eBPF object loading is disabled during compiling.\n");
+	return ERR_PTR(-ENOTSUP);
+}
+
+static inline void bpf__clear(void) { }
+#endif
+#endif
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 02/22] perf tools: Enable passing bpf object file to --event
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
  2015-09-23 11:22 ` [PATCH 01/22] perf ebpf: Add the libbpf glue Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 03/22] perf record, bpf: Create probe points for BPF programs Wang Nan
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	Zefan Li

By introducing new rules in tools/perf/util/parse-events.[ly], this
patch enables 'perf record --event bpf_file.o' to select events by an
eBPF object file. It calls parse_events_load_bpf() to load that file,
which uses bpf__prepare_load() and finally calls bpf_object__open() for
the object files.

After applying this patch, commands like:

 # perf record --event foo.o sleep

become possible.

However, until now this patch is unable to link any useful staff onto
the list because the creating of probe points and BPF program attaching
have not been implemented. Adding this patch before them so following
patches can build them step by step in a testable way.

Before real events are possible to be extracted, to avoid perf report
error because of empty evsel list, this patch link a dummy evsel. The dummy
event related code will be removed when probing and extracting code is
ready.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David Ahern <dsahern@gmail.com>
Cc: He Kuang <hekuang@huawei.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
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/perf.c              |  2 ++
 tools/perf/util/Build          |  1 +
 tools/perf/util/parse-events.c | 56 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.h |  8 ++++++
 tools/perf/util/parse-events.l |  3 +++
 tools/perf/util/parse-events.y | 18 +++++++++++++-
 6 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 1fded92..7a0949e 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -15,6 +15,7 @@
 #include "util/run-command.h"
 #include "util/parse-events.h"
 #include "util/parse-options.h"
+#include "util/bpf-loader.h"
 #include "util/debug.h"
 #include <api/fs/tracing_path.h>
 #include <pthread.h>
@@ -371,6 +372,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 	status = p->fn(argc, argv, prefix);
 	exit_browser(status);
 	perf_env__exit(&perf_env);
+	bpf__clear();
 
 	if (status)
 		return status & 0xff;
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 4bc7a9a..b808151 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -86,6 +86,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o
 libperf-y += parse-branch-options.o
 libperf-y += parse-regs-options.o
 
+libperf-$(CONFIG_LIBBPF) += bpf-loader.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/parse-events.c b/tools/perf/util/parse-events.c
index 61c2bc2..0d4afba 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,7 @@
 #include "symbol.h"
 #include "cache.h"
 #include "header.h"
+#include "bpf-loader.h"
 #include "debug.h"
 #include <api/fs/tracing_path.h>
 #include "parse-events-bison.h"
@@ -515,6 +516,61 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 		return add_tracepoint_event(list, idx, sys, event, error);
 }
 
+int parse_events_load_bpf_obj(struct parse_events_evlist *data,
+			      struct list_head *list,
+			      struct bpf_object *obj)
+{
+	int err;
+	char errbuf[BUFSIZ];
+
+	if (IS_ERR(obj) || !obj) {
+		snprintf(errbuf, sizeof(errbuf),
+			 "Internal error: load bpf obj with NULL");
+		err = -EINVAL;
+		goto errout;
+	}
+
+	/*
+	 * Temporary add a dummy event here so we can check whether
+	 * basic bpf loader works. Will be removed in following patch.
+	 */
+	return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE,
+					PERF_COUNT_SW_DUMMY, NULL);
+errout:
+	data->error->help = strdup("(add -v to see detail)");
+	data->error->str = strdup(errbuf);
+	return err;
+}
+
+int parse_events_load_bpf(struct parse_events_evlist *data,
+			  struct list_head *list,
+			  char *bpf_file_name)
+{
+	struct bpf_object *obj;
+
+	obj = bpf__prepare_load(bpf_file_name);
+	if (IS_ERR(obj) || !obj) {
+		char errbuf[BUFSIZ];
+		int err;
+
+		err = obj ? PTR_ERR(obj) : -EINVAL;
+
+		if (err == -ENOTSUP)
+			snprintf(errbuf, sizeof(errbuf),
+				 "BPF support is not compiled");
+		else
+			snprintf(errbuf, sizeof(errbuf),
+				 "BPF object file '%s' is invalid",
+				 bpf_file_name);
+
+		data->error->help = strdup("(add -v to see detail)");
+		data->error->str = strdup(errbuf);
+		return err;
+	}
+
+	return parse_events_load_bpf_obj(data, list, obj);
+}
+
 static int
 parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ffee7ec..304f587 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -120,6 +120,14 @@ int parse_events_name(struct list_head *list, char *name);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				char *sys, char *event,
 				struct parse_events_error *error);
+int parse_events_load_bpf(struct parse_events_evlist *data,
+			  struct list_head *list,
+			  char *bpf_file_name);
+/* Provide this function for perf test */
+struct bpf_object;
+int parse_events_load_bpf_obj(struct parse_events_evlist *data,
+			      struct list_head *list,
+			      struct bpf_object *obj);
 int parse_events_add_numeric(struct parse_events_evlist *data,
 			     struct list_head *list,
 			     u32 type, u64 config,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 936d566..22e8f93 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -115,6 +115,7 @@ do {							\
 group		[^,{}/]*[{][^}]*[}][^,{}/]*
 event_pmu	[^,{}/]+[/][^/]*[/][^,{}/]*
 event		[^,{}/]+
+bpf_object	.*\.(o|bpf)
 
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
@@ -159,6 +160,7 @@ modifier_bp	[rwx]{1,3}
 		}
 
 {event_pmu}	|
+{bpf_object}	|
 {event}		{
 			BEGIN(INITIAL);
 			REWIND(1);
@@ -264,6 +266,7 @@ r{num_raw_hex}		{ return raw(yyscanner); }
 {num_hex}		{ return value(yyscanner, 16); }
 
 {modifier_event}	{ return str(yyscanner, PE_MODIFIER_EVENT); }
+{bpf_object}		{ return str(yyscanner, PE_BPF_OBJECT); }
 {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 8bcc458..3bc79b2 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -42,6 +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_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
@@ -53,6 +54,7 @@ static inc_group_count(struct list_head *list,
 %type <num> PE_RAW
 %type <num> PE_TERM
 %type <str> PE_NAME
+%type <str> PE_BPF_OBJECT
 %type <str> PE_NAME_CACHE_TYPE
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
@@ -69,6 +71,7 @@ static inc_group_count(struct list_head *list,
 %type <head> event_legacy_tracepoint
 %type <head> event_legacy_numeric
 %type <head> event_legacy_raw
+%type <head> event_bpf_file
 %type <head> event_def
 %type <head> event_mod
 %type <head> event_name
@@ -198,7 +201,8 @@ event_def: event_pmu |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
 	   event_legacy_numeric sep_dc |
-	   event_legacy_raw sep_dc
+	   event_legacy_raw sep_dc |
+	   event_bpf_file
 
 event_pmu:
 PE_NAME '/' event_config '/'
@@ -422,6 +426,18 @@ PE_RAW
 	$$ = list;
 }
 
+event_bpf_file:
+PE_BPF_OBJECT
+{
+	struct parse_events_evlist *data = _data;
+	struct parse_events_error *error = data->error;
+	struct list_head *list;
+
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_load_bpf(data, list, $1));
+	$$ = list;
+}
+
 start_terms: event_config
 {
 	struct parse_events_terms *data = _data;
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 03/22] perf record, bpf: Create probe points for BPF programs
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
  2015-09-23 11:22 ` [PATCH 01/22] perf ebpf: Add the libbpf glue Wang Nan
  2015-09-23 11:22 ` [PATCH 02/22] perf tools: Enable passing bpf object file to --event Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 04/22] perf record: Load eBPF object into kernel Wang Nan
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch introduces bpf__{un,}probe() functions to enable callers to
create kprobe points based on section names a BPF program. It parses
the section names in the program and creates corresponding 'struct
perf_probe_event' structures. The parse_perf_probe_command() function is
used to do the main parsing work. The resuling 'struct perf_probe_event'
is stored into program private data for further using.

By utilizing the new probing API, this patch creates probe points during
event parsing.

To ensure probe points be removed correctly, register an atexit hook
so even perf quit through exit() bpf__clear() is still called, so probing
points are cleared.

strerror style error reporting scaffold is created by this patch.
bpf__strerror_probe() is the first error reporting function in bpf-loader.c.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.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/util/bpf-loader.c   | 221 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/bpf-loader.h   |  30 ++++++
 tools/perf/util/parse-events.c |  12 +++
 3 files changed, 262 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index ab56073..1a10b6c 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -10,6 +10,8 @@
 #include "perf.h"
 #include "debug.h"
 #include "bpf-loader.h"
+#include "probe-event.h"
+#include "probe-finder.h" // for MAX_PROBES
 
 #define DEFINE_PRINT_FN(name, level) \
 static int libbpf_##name(const char *fmt, ...)	\
@@ -27,6 +29,10 @@ DEFINE_PRINT_FN(warning, 0)
 DEFINE_PRINT_FN(info, 0)
 DEFINE_PRINT_FN(debug, 1)
 
+struct bpf_prog_priv {
+	struct perf_probe_event pev;
+};
+
 struct bpf_object *bpf__prepare_load(const char *filename)
 {
 	struct bpf_object *obj;
@@ -52,6 +58,219 @@ void bpf__clear(void)
 {
 	struct bpf_object *obj, *tmp;
 
-	bpf_object__for_each_safe(obj, tmp)
+	bpf_object__for_each_safe(obj, tmp) {
+		bpf__unprobe(obj);
 		bpf_object__close(obj);
+	}
+}
+
+static void
+bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
+		     void *_priv)
+{
+	struct bpf_prog_priv *priv = _priv;
+
+	cleanup_perf_probe_events(&priv->pev, 1);
+	free(priv);
+}
+
+static int
+config_bpf_program(struct bpf_program *prog)
+{
+	struct perf_probe_event *pev = NULL;
+	struct bpf_prog_priv *priv = NULL;
+	const char *config_str;
+	int err;
+
+	config_str = bpf_program__title(prog, false);
+	if (!config_str) {
+		pr_debug("bpf: unable to get title for program\n");
+		return -EINVAL;
+	}
+
+	priv = calloc(sizeof(*priv), 1);
+	if (!priv) {
+		pr_debug("bpf: failed to alloc priv\n");
+		return -ENOMEM;
+	}
+	pev = &priv->pev;
+
+	pr_debug("bpf: config program '%s'\n", config_str);
+	err = parse_perf_probe_command(config_str, pev);
+	if (err < 0) {
+		pr_debug("bpf: '%s' is not a valid config string\n",
+			 config_str);
+		err = -EINVAL;
+		goto errout;
+	}
+
+	if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
+		pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
+			 config_str, PERF_BPF_PROBE_GROUP);
+		err = -EINVAL;
+		goto errout;
+	} else if (!pev->group)
+		pev->group = strdup(PERF_BPF_PROBE_GROUP);
+
+	if (!pev->group) {
+		pr_debug("bpf: strdup failed\n");
+		err = -ENOMEM;
+		goto errout;
+	}
+
+	if (!pev->event) {
+		pr_debug("bpf: '%s': event name is missing\n",
+			 config_str);
+		err = -EINVAL;
+		goto errout;
+	}
+	pr_debug("bpf: config '%s' is ok\n", config_str);
+
+	err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear);
+	if (err) {
+		pr_debug("Failed to set priv for program '%s'\n", config_str);
+		goto errout;
+	}
+
+	return 0;
+
+errout:
+	if (pev)
+		clear_perf_probe_event(pev);
+	free(priv);
+	return err;
+}
+
+static int bpf__prepare_probe(void)
+{
+	static int err = 0;
+	static bool initialized = false;
+
+	/*
+	 * Make err static, so if init failed the first, bpf__prepare_probe()
+	 * fails each time without calling init_probe_symbol_maps multiple
+	 * times.
+	 */
+	if (initialized)
+		return err;
+
+	initialized = true;
+	err = init_probe_symbol_maps(false);
+	if (err < 0)
+		pr_debug("Failed to init_probe_symbol_maps\n");
+	probe_conf.max_probes = MAX_PROBES;
+	return err;
+}
+
+int bpf__probe(struct bpf_object *obj)
+{
+	int err = 0;
+	struct bpf_program *prog;
+	struct bpf_prog_priv *priv;
+	struct perf_probe_event *pev;
+
+	err = bpf__prepare_probe();
+	if (err) {
+		pr_debug("bpf__prepare_probe failed\n");
+		return err;
+	}
+
+	bpf_object__for_each_program(prog, obj) {
+		err = config_bpf_program(prog);
+		if (err)
+			goto out;
+
+		err = bpf_program__get_private(prog, (void **)&priv);
+		if (err || !priv)
+			goto out;
+		pev = &priv->pev;
+
+		err = convert_perf_probe_events(pev, 1);
+		if (err < 0) {
+			pr_debug("bpf_probe: failed to convert perf probe events");
+			goto out;
+		}
+
+		err = apply_perf_probe_events(pev, 1);
+		if (err < 0) {
+			pr_debug("bpf_probe: failed to apply perf probe events");
+			goto out;
+		}
+	}
+out:
+	return err < 0 ? err : 0;
+}
+
+#define EVENTS_WRITE_BUFSIZE  4096
+int bpf__unprobe(struct bpf_object *obj)
+{
+	int err, ret = 0;
+	struct bpf_program *prog;
+	struct bpf_prog_priv *priv;
+
+	bpf_object__for_each_program(prog, obj) {
+		int i;
+
+		err = bpf_program__get_private(prog, (void **)&priv);
+		if (err || !priv)
+			continue;
+
+		for (i = 0; i < priv->pev.ntevs; i++) {
+			struct probe_trace_event *tev = &priv->pev.tevs[i];
+			char name_buf[EVENTS_WRITE_BUFSIZE];
+			struct strfilter *delfilter;
+
+			snprintf(name_buf, EVENTS_WRITE_BUFSIZE,
+				 "%s:%s", tev->group, tev->event);
+
+			delfilter = strfilter__new(name_buf, NULL);
+			if (!delfilter) {
+				pr_debug("Failed to create filter for unprobing\n");
+				ret = -ENOMEM;
+				continue;
+			}
+
+			err = del_perf_probe_events(delfilter);
+			strfilter__delete(delfilter);
+			if (err) {
+				pr_debug("Failed to delete %s\n", name_buf);
+				ret = err;
+				continue;
+			}
+		}
+	}
+	return ret;
+}
+
+#define bpf__strerror_head(err, buf, size) \
+	char sbuf[STRERR_BUFSIZE], *emsg;\
+	if (!size)\
+		return 0;\
+	if (err < 0)\
+		err = -err;\
+	emsg = strerror_r(err, sbuf, sizeof(sbuf));\
+	switch (err) {\
+	default:\
+		scnprintf(buf, size, "%s", emsg);\
+		break;
+
+#define bpf__strerror_entry(val, fmt...)\
+	case val: {\
+		scnprintf(buf, size, fmt);\
+		break;\
+	}
+
+#define bpf__strerror_end(buf, size)\
+	}\
+	buf[size - 1] = '\0';
+
+int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
+			int err, char *buf, size_t size)
+{
+	bpf__strerror_head(err, buf, size);
+	bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
+	bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n");
+	bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n");
+	bpf__strerror_end(buf, size);
+	return 0;
 }
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index f402d7c..b819622 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -11,11 +11,18 @@
 #include "debug.h"
 
 struct bpf_object;
+#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
 
 #ifdef HAVE_LIBBPF_SUPPORT
 struct bpf_object *bpf__prepare_load(const char *filename);
 
 void bpf__clear(void);
+
+int bpf__probe(struct bpf_object *obj);
+int bpf__unprobe(struct bpf_object *obj);
+int bpf__strerror_probe(struct bpf_object *obj, int err,
+			char *buf, size_t size);
+
 #else
 static inline struct bpf_object *
 bpf__prepare_load(const char *filename __maybe_unused)
@@ -25,5 +32,28 @@ bpf__prepare_load(const char *filename __maybe_unused)
 }
 
 static inline void bpf__clear(void) { }
+
+static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
+static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;}
+
+static inline int
+__bpf_strerror(char *buf, size_t size)
+{
+	if (!size)
+		return 0;
+	strncpy(buf,
+		"ERROR: eBPF object loading is disabled during compiling.\n",
+		size);
+	buf[size - 1] = '\0';
+	return 0;
+}
+
+static inline int
+bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
+		    int err __maybe_unused,
+		    char *buf, size_t size)
+{
+	return __bpf_strerror(buf, size);
+}
 #endif
 #endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 0d4afba..354da59 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -522,6 +522,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 {
 	int err;
 	char errbuf[BUFSIZ];
+	static bool registered_unprobe_atexit = false;
 
 	if (IS_ERR(obj) || !obj) {
 		snprintf(errbuf, sizeof(errbuf),
@@ -530,6 +531,17 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 		goto errout;
 	}
 
+	err = bpf__probe(obj);
+	if (err) {
+		bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf));
+		goto errout;
+	}
+
+	if (!registered_unprobe_atexit) {
+		atexit(bpf__clear);
+		registered_unprobe_atexit = true;
+	}
+
 	/*
 	 * Temporary add a dummy event here so we can check whether
 	 * basic bpf loader works. Will be removed in following patch.
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 04/22] perf record: Load eBPF object into kernel
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (2 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 03/22] perf record, bpf: Create probe points for BPF programs Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 05/22] perf tools: Collect perf_evsel in BPF object files Wang Nan
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch utilizes bpf_object__load() provided by libbpf to load all
objects into kernel.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c   | 22 ++++++++++++++++++++++
 tools/perf/util/bpf-loader.h   | 11 +++++++++++
 tools/perf/util/parse-events.c |  6 ++++++
 3 files changed, 39 insertions(+)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 1a10b6c..39732a4 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -242,6 +242,18 @@ int bpf__unprobe(struct bpf_object *obj)
 	return ret;
 }
 
+int bpf__load(struct bpf_object *obj)
+{
+	int err;
+
+	err = bpf_object__load(obj);
+	if (err) {
+		pr_debug("bpf: load objects failed\n");
+		return err;
+	}
+	return 0;
+}
+
 #define bpf__strerror_head(err, buf, size) \
 	char sbuf[STRERR_BUFSIZE], *emsg;\
 	if (!size)\
@@ -274,3 +286,13 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
 	bpf__strerror_end(buf, size);
 	return 0;
 }
+
+int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
+		       int err, char *buf, size_t size)
+{
+	bpf__strerror_head(err, buf, size);
+	bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?",
+			    emsg)
+	bpf__strerror_end(buf, size);
+	return 0;
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index b819622..b091ceb 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -23,6 +23,9 @@ int bpf__unprobe(struct bpf_object *obj);
 int bpf__strerror_probe(struct bpf_object *obj, int err,
 			char *buf, size_t size);
 
+int bpf__load(struct bpf_object *obj);
+int bpf__strerror_load(struct bpf_object *obj, int err,
+		       char *buf, size_t size);
 #else
 static inline struct bpf_object *
 bpf__prepare_load(const char *filename __maybe_unused)
@@ -35,6 +38,7 @@ static inline void bpf__clear(void) { }
 
 static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
 static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;}
+static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; }
 
 static inline int
 __bpf_strerror(char *buf, size_t size)
@@ -55,5 +59,12 @@ bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
 {
 	return __bpf_strerror(buf, size);
 }
+
+static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
+				     int err __maybe_unused,
+				     char *buf, size_t size)
+{
+	return __bpf_strerror(buf, size);
+}
 #endif
 #endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 354da59..a7152f3 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -542,6 +542,12 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 		registered_unprobe_atexit = true;
 	}
 
+	err = bpf__load(obj);
+	if (err) {
+		bpf__strerror_load(obj, err, errbuf, sizeof(errbuf));
+		goto errout;
+	}
+
 	/*
 	 * Temporary add a dummy event here so we can check whether
 	 * basic bpf loader works. Will be removed in following patch.
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 05/22] perf tools: Collect perf_evsel in BPF object files
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (3 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 04/22] perf record: Load eBPF object into kernel Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 06/22] perf tools: Attach eBPF program to perf event Wang Nan
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch collects 'struct perf_evsel' for every probing points in BPF
object file(s) and fill 'struct evlist'. The previous introduced dummy
event now removed. After this patch, following command:

 # perf record --event filter.o ls

Can trace on each probing points defined in filter.o.

The core of this patch is bpf__foreach_tev(), which calls a callback
function for each 'struct probe_trace_event' events for a bpf program
with their file descriptors. Callback function add_bpf_event()
creates evsels by calling parse_events_add_tracepoint().

Since bpf-loader.c will not be built if libbpf is turned off, an empty
bpf__foreach_tev() is defined in bpf-loader.h to avoid compiling
error.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c   | 40 +++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h   | 15 +++++++++++++
 tools/perf/util/parse-events.c | 48 ++++++++++++++++++++++++++++++++++++------
 3 files changed, 97 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 39732a4..33e592c 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -254,6 +254,46 @@ int bpf__load(struct bpf_object *obj)
 	return 0;
 }
 
+int bpf__foreach_tev(struct bpf_object *obj,
+		     bpf_prog_iter_callback_t func,
+		     void *arg)
+{
+	struct bpf_program *prog;
+	int err;
+
+	bpf_object__for_each_program(prog, obj) {
+		struct probe_trace_event *tev;
+		struct perf_probe_event *pev;
+		struct bpf_prog_priv *priv;
+		int i, fd;
+
+		err = bpf_program__get_private(prog,
+				(void **)&priv);
+		if (err || !priv) {
+			pr_debug("bpf: failed to get private field\n");
+			return -EINVAL;
+		}
+
+		pev = &priv->pev;
+		for (i = 0; i < pev->ntevs; i++) {
+			tev = &pev->tevs[i];
+
+			fd = bpf_program__fd(prog);
+			if (fd < 0) {
+				pr_debug("bpf: failed to get file descriptor\n");
+				return fd;
+			}
+
+			err = (*func)(tev, fd, arg);
+			if (err) {
+				pr_debug("bpf: call back failed, stop iterate\n");
+				return err;
+			}
+		}
+	}
+	return 0;
+}
+
 #define bpf__strerror_head(err, buf, size) \
 	char sbuf[STRERR_BUFSIZE], *emsg;\
 	if (!size)\
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index b091ceb..4adfc03 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,11 +8,15 @@
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <string.h>
+#include "probe-event.h"
 #include "debug.h"
 
 struct bpf_object;
 #define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
 
+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);
 
@@ -26,6 +30,9 @@ int bpf__strerror_probe(struct bpf_object *obj, int err,
 int bpf__load(struct bpf_object *obj);
 int bpf__strerror_load(struct bpf_object *obj, int err,
 		       char *buf, size_t size);
+
+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)
@@ -41,6 +48,14 @@ static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0
 static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; }
 
 static inline int
+bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
+		 bpf_prog_iter_callback_t func __maybe_unused,
+		 void *arg __maybe_unused)
+{
+	return 0;
+}
+
+static inline int
 __bpf_strerror(char *buf, size_t size)
 {
 	if (!size)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a7152f3..c3505fb 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -516,6 +516,39 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 		return add_tracepoint_event(list, idx, sys, event, error);
 }
 
+struct __add_bpf_event_param {
+	struct parse_events_evlist *data;
+	struct list_head *list;
+};
+
+static int add_bpf_event(struct probe_trace_event *tev, int fd,
+			 void *_param)
+{
+	struct __add_bpf_event_param *param = _param;
+	struct parse_events_evlist *evlist = param->data;
+	struct list_head *list = param->list;
+	int err;
+
+	pr_debug("add bpf event %s:%s and attach bpf program %d\n",
+			tev->group, tev->event, fd);
+
+	err = parse_events_add_tracepoint(list, &evlist->idx, tev->group,
+					  tev->event, evlist->error);
+	if (err) {
+		struct perf_evsel *evsel, *tmp;
+
+		pr_debug("Failed to add BPF event %s:%s\n",
+			 tev->group, tev->event);
+		list_for_each_entry_safe(evsel, tmp, list, node) {
+			list_del(&evsel->node);
+			perf_evsel__delete(evsel);
+		}
+		return err;
+	}
+	pr_debug("adding %s:%s\n", tev->group, tev->event);
+	return 0;
+}
+
 int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 			      struct list_head *list,
 			      struct bpf_object *obj)
@@ -523,6 +556,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 	int err;
 	char errbuf[BUFSIZ];
 	static bool registered_unprobe_atexit = false;
+	struct __add_bpf_event_param param = {data, list};
 
 	if (IS_ERR(obj) || !obj) {
 		snprintf(errbuf, sizeof(errbuf),
@@ -548,12 +582,14 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
 		goto errout;
 	}
 
-	/*
-	 * Temporary add a dummy event here so we can check whether
-	 * basic bpf loader works. Will be removed in following patch.
-	 */
-	return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE,
-					PERF_COUNT_SW_DUMMY, NULL);
+	err = bpf__foreach_tev(obj, add_bpf_event, &param);
+	if (err) {
+		snprintf(errbuf, sizeof(errbuf),
+			 "Attach events in BPF object failed");
+		goto errout;
+	}
+
+	return 0;
 errout:
 	data->error->help = strdup("(add -v to see detail)");
 	data->error->str = strdup(errbuf);
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 06/22] perf tools: Attach eBPF program to perf event
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (4 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 05/22] perf tools: Collect perf_evsel in BPF object files Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 07/22] perf record: Add clang options for compiling BPF scripts Wang Nan
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This is the final patch which makes basic BPF filter work. After
applying this patch, users are allowed to use BPF filter like:

 # perf record --event ./hello_world.o ls

A bpf_fd field is appended to 'struct evsel', and setup during the
callback function add_bpf_event() for each 'probe_trace_event'.

PERF_EVENT_IOC_SET_BPF ioctl is used to attach eBPF program to a newly
created perf event. The file descriptor of the eBPF program is passed to
perf record using previous patches, and stored into evsel->bpf_fd.

It is possible that different perf event are created for one kprobe
events for different CPUs. In this case, when trying to call the
ioctl, EEXIST will be return. This patch doesn't treat it as an error.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/evsel.c        | 17 +++++++++++++++++
 tools/perf/util/evsel.h        |  1 +
 tools/perf/util/parse-events.c |  4 ++++
 3 files changed, 22 insertions(+)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5889004..3f69d72 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -208,6 +208,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
 	evsel->unit	   = "";
 	evsel->scale	   = 1.0;
 	evsel->evlist	   = NULL;
+	evsel->bpf_fd	   = -1;
 	INIT_LIST_HEAD(&evsel->node);
 	INIT_LIST_HEAD(&evsel->config_terms);
 	perf_evsel__object.init(evsel);
@@ -1343,6 +1344,22 @@ retry_open:
 					  err);
 				goto try_fallback;
 			}
+
+			if (evsel->bpf_fd >= 0) {
+				int evt_fd = FD(evsel, cpu, thread);
+				int bpf_fd = evsel->bpf_fd;
+
+				err = ioctl(evt_fd,
+					    PERF_EVENT_IOC_SET_BPF,
+					    bpf_fd);
+				if (err && errno != EEXIST) {
+					pr_err("failed to attach bpf fd %d: %s\n",
+					       bpf_fd, strerror(errno));
+					err = -EINVAL;
+					goto out_close;
+				}
+			}
+
 			set_rlimit = NO_CHANGE;
 
 			/*
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 7906666..96f1294 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -120,6 +120,7 @@ struct perf_evsel {
 	char			*group_name;
 	bool			cmdline_group_boundary;
 	struct list_head	config_terms;
+	int			bpf_fd;
 };
 
 union u64_swap {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c3505fb..37cb196 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -527,6 +527,7 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
 	struct __add_bpf_event_param *param = _param;
 	struct parse_events_evlist *evlist = param->data;
 	struct list_head *list = param->list;
+	struct perf_evsel *pos;
 	int err;
 
 	pr_debug("add bpf event %s:%s and attach bpf program %d\n",
@@ -546,6 +547,9 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
 		return err;
 	}
 	pr_debug("adding %s:%s\n", tev->group, tev->event);
+
+	list_for_each_entry(pos, list, node)
+		pos->bpf_fd = fd;
 	return 0;
 }
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 07/22] perf record: Add clang options for compiling BPF scripts
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (5 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 06/22] perf tools: Attach eBPF program to perf event Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 08/22] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event Wang Nan
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

Although previous patch allows setting BPF compiler related options in
perfconfig, on some ad-hoc situation it still requires passing options
through cmdline. This patch introduces 2 options to 'perf record' for
this propose: --clang-path and --clang-opt.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/builtin-record.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 142eeb3..ea3eef6 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,6 +31,7 @@
 #include "util/auxtrace.h"
 #include "util/parse-branch-options.h"
 #include "util/parse-regs-options.h"
+#include "util/llvm-utils.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -1096,6 +1097,12 @@ struct option __record_options[] = {
 			"per thread proc mmap processing timeout in ms"),
 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
 		    "Record context switch events"),
+#ifdef HAVE_LIBBPF_SUPPORT
+	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
+		   "clang binary to use for compiling BPF scriptlets"),
+	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
+		   "options passed to clang when compiling BPF scriptlets"),
+#endif
 	OPT_END()
 };
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 08/22] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (6 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 07/22] perf record: Add clang options for compiling BPF scripts Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 09/22] perf test: Enforce LLVM test for BPF test Wang Nan
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, He Kuang, Brendan Gregg,
	Daniel Borkmann, David Ahern, Jiri Olsa, Kaixu Xia,
	Masami Hiramatsu, Namhyung Kim, Peter Zijlstra, Zefan Li

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
@@ -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 33e592c..286d3a9 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 4adfc03..fc6eb24 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);
 
@@ -35,7 +35,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 37cb196..22406be 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -602,11 +602,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 304f587..c65c130 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -122,7 +122,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				struct parse_events_error *error);
 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 22e8f93..8033890 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 3bc79b2..9aeb632 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
@@ -434,7 +435,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


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 09/22] perf test: Enforce LLVM test for BPF test
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (7 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 08/22] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 10/22] perf test: Add 'perf test BPF' Wang Nan
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, He Kuang, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	Zefan Li

This patch replaces the original toy BPF program with previous introduced
bpf-script-example.c. Dynamically embedded it into 'llvm-src.c'.

The newly introduced BPF program attaches a BPF program at
'sys_epoll_pwait()', and collect half samples from it. perf itself never
use that syscall, so further test can verify their result with it.

Since BPF program require LINUX_VERSION_CODE of runtime kernel, this
patch computes that code from uname.

Since the resuling BPF object is useful for further testcases, this patch
introduces 'prepare' and 'cleanup' method to tests, and makes test__llvm()
create a MAP_SHARED memory array to hold the resulting object.

Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: 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
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/tests/Build          |   9 +++-
 tools/perf/tests/builtin-test.c |   8 ++++
 tools/perf/tests/llvm.c         | 104 +++++++++++++++++++++++++++++++++++-----
 tools/perf/tests/llvm.h         |  14 ++++++
 tools/perf/tests/tests.h        |   2 +
 5 files changed, 123 insertions(+), 14 deletions(-)
 create mode 100644 tools/perf/tests/llvm.h

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index c6f198ae..e80f787 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,9 +32,16 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
-perf-y += llvm.o
+perf-y += llvm.o llvm-src.o
 perf-y += topology.o
 
+$(OUTPUT)tests/llvm-src.c: tests/bpf-script-example.c
+	$(call rule_mkdir)
+	$(Q)echo '#include <tests/llvm.h>' > $@
+	$(Q)echo 'const char test_llvm__bpf_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 ifdef CONFIG_AUXTRACE
 perf-$(CONFIG_X86) += insn-x86.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d9bf51d..09f3eb8 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -17,6 +17,8 @@
 static struct test {
 	const char *desc;
 	int (*func)(void);
+	void (*prepare)(void);
+	void (*cleanup)(void);
 } tests[] = {
 	{
 		.desc = "vmlinux symtab matches kallsyms",
@@ -177,6 +179,8 @@ static struct test {
 	{
 		.desc = "Test LLVM searching and compiling",
 		.func = test__llvm,
+		.prepare = test__llvm_prepare,
+		.cleanup = test__llvm_cleanup,
 	},
 #ifdef HAVE_AUXTRACE_SUPPORT
 #if defined(__x86_64__) || defined(__i386__)
@@ -278,7 +282,11 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 		}
 
 		pr_debug("\n--- start ---\n");
+		if (t->prepare)
+			t->prepare();
 		err = run_test(t);
+		if (t->cleanup)
+			t->cleanup();
 		pr_debug("---- end ----\n%s:", t->desc);
 
 		switch (err) {
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 52d5597..236bf39 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -1,9 +1,13 @@
 #include <stdio.h>
+#include <sys/utsname.h>
 #include <bpf/libbpf.h>
 #include <util/llvm-utils.h>
 #include <util/cache.h>
+#include <util/util.h>
+#include <sys/mman.h>
 #include "tests.h"
 #include "debug.h"
+#include "llvm.h"
 
 static int perf_config_cb(const char *var, const char *val,
 			  void *arg __maybe_unused)
@@ -11,16 +15,6 @@ static int perf_config_cb(const char *var, const char *val,
 	return perf_default_config(var, val, arg);
 }
 
-/*
- * Randomly give it a "version" section since we don't really load it
- * into kernel
- */
-static const char test_bpf_prog[] =
-	"__attribute__((section(\"do_fork\"), used)) "
-	"int fork(void *ctx) {return 0;} "
-	"char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
-	"int _version __attribute__((section(\"version\"), used)) = 0x40100;";
-
 #ifdef HAVE_LIBBPF_SUPPORT
 static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
 {
@@ -41,12 +35,44 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
 }
 #endif
 
+static char *
+compose_source(void)
+{
+	struct utsname utsname;
+	int version, patchlevel, sublevel, err;
+	unsigned long version_code;
+	char *code;
+
+	if (uname(&utsname))
+		return NULL;
+
+	err = sscanf(utsname.release, "%d.%d.%d",
+		     &version, &patchlevel, &sublevel);
+	if (err != 3) {
+		fprintf(stderr, " (Can't get kernel version from uname '%s')",
+			utsname.release);
+		return NULL;
+	}
+
+	version_code = (version << 16) + (patchlevel << 8) + sublevel;
+	err = asprintf(&code, "#define LINUX_VERSION_CODE 0x%08lx;\n%s",
+		       version_code, test_llvm__bpf_prog);
+	if (err < 0)
+		return NULL;
+
+	return code;
+}
+
+#define SHARED_BUF_INIT_SIZE	(1 << 20)
+struct test_llvm__bpf_result *p_test_llvm__bpf_result;
+
 int test__llvm(void)
 {
 	char *tmpl_new, *clang_opt_new;
 	void *obj_buf;
 	size_t obj_buf_sz;
 	int err, old_verbose;
+	char *source;
 
 	perf_config(perf_config_cb, NULL);
 
@@ -73,10 +99,22 @@ int test__llvm(void)
 	if (!llvm_param.clang_opt)
 		llvm_param.clang_opt = strdup("");
 
-	err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog,
-		       llvm_param.clang_bpf_cmd_template);
-	if (err < 0)
+	source = compose_source();
+	if (!source) {
+		pr_err("Failed to compose source code\n");
+		return -1;
+	}
+
+	/* Quote __EOF__ so strings in source won't be expanded by shell */
+	err = asprintf(&tmpl_new, "cat << '__EOF__' | %s\n%s\n__EOF__\n",
+		       llvm_param.clang_bpf_cmd_template, source);
+	free(source);
+	source = NULL;
+	if (err < 0) {
+		pr_err("Failed to alloc new template\n");
 		return -1;
+	}
+
 	err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
 	if (err < 0)
 		return -1;
@@ -93,6 +131,46 @@ int test__llvm(void)
 	}
 
 	err = test__bpf_parsing(obj_buf, obj_buf_sz);
+	if (!err && p_test_llvm__bpf_result) {
+		if (obj_buf_sz > SHARED_BUF_INIT_SIZE) {
+			pr_err("Resulting object too large\n");
+		} else {
+			p_test_llvm__bpf_result->size = obj_buf_sz;
+			memcpy(p_test_llvm__bpf_result->object,
+			       obj_buf, obj_buf_sz);
+		}
+	}
 	free(obj_buf);
 	return err;
 }
+
+void test__llvm_prepare(void)
+{
+	p_test_llvm__bpf_result = mmap(NULL, SHARED_BUF_INIT_SIZE,
+				       PROT_READ | PROT_WRITE,
+				       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if (!p_test_llvm__bpf_result)
+		return;
+	memset((void *)p_test_llvm__bpf_result, '\0', SHARED_BUF_INIT_SIZE);
+}
+
+void test__llvm_cleanup(void)
+{
+	unsigned long boundary, buf_end;
+
+	if (!p_test_llvm__bpf_result)
+		return;
+	if (p_test_llvm__bpf_result->size == 0) {
+		munmap((void *)p_test_llvm__bpf_result, SHARED_BUF_INIT_SIZE);
+		p_test_llvm__bpf_result = NULL;
+		return;
+	}
+
+	buf_end = (unsigned long)p_test_llvm__bpf_result + SHARED_BUF_INIT_SIZE;
+
+	boundary = (unsigned long)(p_test_llvm__bpf_result);
+	boundary += p_test_llvm__bpf_result->size;
+	boundary = (boundary + (page_size - 1)) &
+			(~((unsigned long)page_size - 1));
+	munmap((void *)boundary, buf_end - boundary);
+}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 0000000..1e89e46
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,14 @@
+#ifndef PERF_TEST_LLVM_H
+#define PERF_TEST_LLVM_H
+
+#include <stddef.h> /* for size_t */
+
+struct test_llvm__bpf_result {
+	size_t size;
+	char object[];
+};
+
+extern struct test_llvm__bpf_result *p_test_llvm__bpf_result;
+extern const char test_llvm__bpf_prog[];
+
+#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0b35496..a5e6f641 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -63,6 +63,8 @@ int test__fdarray__add(void);
 int test__kmod_path__parse(void);
 int test__thread_map(void);
 int test__llvm(void);
+void test__llvm_prepare(void);
+void test__llvm_cleanup(void);
 int test__insn_x86(void);
 int test_session_topology(void);
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 10/22] perf test: Add 'perf test BPF'
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (8 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 09/22] perf test: Enforce LLVM test for BPF test Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 11/22] perf probe: Reset args and nargs for probe_trace_event when failure Wang Nan
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	Zefan Li

This patch adds BPF testcase for testing BPF event filtering.

By utilizing the result of 'perf test LLVM', this patch compiles the
eBPF sample program then test it ability. The BPF script in 'perf test
LLVM' collects half of execution of epoll_pwait(). This patch runs 111
times of it, so the resule should contains 56 samples.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: 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: He Kuang <hekuang@huawei.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
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/tests/Build          |   1 +
 tools/perf/tests/bpf.c          | 171 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c |   4 +
 tools/perf/tests/llvm.c         |  19 +++++
 tools/perf/tests/llvm.h         |   1 +
 tools/perf/tests/tests.h        |   1 +
 tools/perf/util/bpf-loader.c    |  14 ++++
 tools/perf/util/bpf-loader.h    |   9 +++
 8 files changed, 220 insertions(+)
 create mode 100644 tools/perf/tests/bpf.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index e80f787..5cfb420 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
 perf-y += llvm.o llvm-src.o
+perf-y += bpf.o
 perf-y += topology.o
 
 $(OUTPUT)tests/llvm-src.c: tests/bpf-script-example.c
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
new file mode 100644
index 0000000..d7cdc84
--- /dev/null
+++ b/tools/perf/tests/bpf.c
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <util/bpf-loader.h>
+#include <util/evlist.h>
+#include "tests.h"
+#include "llvm.h"
+#include "debug.h"
+#define NR_ITERS       111
+
+#ifdef HAVE_LIBBPF_SUPPORT
+
+static int epoll_pwait_loop(void)
+{
+	int i;
+
+	/* Should fail NR_ITERS times */
+	for (i = 0; i < NR_ITERS; i++)
+		epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
+	return 0;
+}
+
+static struct bpf_object *prepare_bpf(void *obj_buf, size_t obj_buf_sz)
+{
+	struct bpf_object *obj;
+
+	obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, "[buffer]");
+	if (IS_ERR(obj)) {
+		fprintf(stderr, " (compile failed)");
+		return NULL;
+	}
+	return obj;
+}
+
+static int do_test(struct bpf_object *obj)
+{
+	struct record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
+		.freq	      = 0,
+		.mmap_pages   = 256,
+		.default_interval = 1,
+	};
+
+	int i, err = 0, count = 0;
+	char pid[16];
+	char sbuf[STRERR_BUFSIZE];
+	struct perf_evlist *evlist;
+
+	struct parse_events_evlist parse_evlist;
+	struct parse_events_error parse_error;
+
+	bzero(&parse_error, sizeof(parse_error));
+	bzero(&parse_evlist, sizeof(parse_evlist));
+	parse_evlist.error = &parse_error;
+	INIT_LIST_HEAD(&parse_evlist.list);
+
+	err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
+	if (err || list_empty(&parse_evlist.list)) {
+		fprintf(stderr, " (Failed to add events selected by BPF)");
+		if (!err)
+			err = -EINVAL;
+		goto out;
+	}
+
+	snprintf(pid, sizeof(pid), "%d", getpid());
+	pid[sizeof(pid) - 1] = '\0';
+	opts.target.tid = opts.target.pid = pid;
+
+	/* Instead of perf_evlist__new_default, don't add default events */
+	evlist = perf_evlist__new();
+	if (!evlist) {
+		pr_debug("No ehough memory to create evlist\n");
+		return -ENOMEM;
+	}
+
+	err = perf_evlist__create_maps(evlist, &opts.target);
+	if (err < 0) {
+		pr_debug("Not enough memory to create thread/cpu maps\n");
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
+	evlist->nr_groups = parse_evlist.nr_groups;
+
+	perf_evlist__config(evlist, &opts);
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		pr_debug("perf_evlist__open: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		goto out_delete_evlist;
+	}
+
+	err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
+	if (err < 0) {
+		pr_debug("perf_evlist__mmap: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__enable(evlist);
+	epoll_pwait_loop();
+	perf_evlist__disable(evlist);
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		union perf_event *event;
+
+		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+			const u32 type = event->header.type;
+
+			if (type == PERF_RECORD_SAMPLE)
+				count ++;
+		}
+	}
+
+	if (count != (NR_ITERS + 1) / 2) {
+		fprintf(stderr, " (filter result incorrect)");
+		err = -EBADF;
+	}
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+out:
+	if (err)
+		return TEST_FAIL;
+	return 0;
+}
+
+int test__bpf(void)
+{
+	int err;
+	void *obj_buf;
+	size_t obj_buf_sz;
+	struct bpf_object *obj;
+
+	if (geteuid() != 0) {
+		fprintf(stderr, " (try run as root)");
+		return TEST_SKIP;
+	}
+
+	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz);
+	if (!obj_buf || !obj_buf_sz) {
+		if (verbose == 0)
+			fprintf(stderr, " (fix 'perf test LLVM' first)");
+		return TEST_SKIP;
+	}
+
+	obj = prepare_bpf(obj_buf, obj_buf_sz);
+	if (!obj) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = do_test(obj);
+	if (err)
+		goto out;
+out:
+	bpf__clear();
+	if (err)
+		return TEST_FAIL;
+	return 0;
+}
+
+#else
+int test__bpf(void)
+{
+	return TEST_SKIP;
+}
+#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 09f3eb8..2cb19fe 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -195,6 +195,10 @@ static struct test {
 		.func = test_session_topology,
 	},
 	{
+		.desc = "Test BPF filter",
+		.func = test__bpf,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 236bf39..fd5fdb0 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -174,3 +174,22 @@ void test__llvm_cleanup(void)
 			(~((unsigned long)page_size - 1));
 	munmap((void *)boundary, buf_end - boundary);
 }
+
+void
+test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz)
+{
+	*p_obj_buf = NULL;
+	*p_obj_buf_sz = 0;
+
+	if (!p_test_llvm__bpf_result) {
+		test__llvm_prepare();
+		test__llvm();
+		test__llvm_cleanup();
+	}
+
+	if (!p_test_llvm__bpf_result)
+		return;
+
+	*p_obj_buf = p_test_llvm__bpf_result->object;
+	*p_obj_buf_sz = p_test_llvm__bpf_result->size;
+}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 1e89e46..2fd7ed6 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -10,5 +10,6 @@ struct test_llvm__bpf_result {
 
 extern struct test_llvm__bpf_result *p_test_llvm__bpf_result;
 extern const char test_llvm__bpf_prog[];
+void test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz);
 
 #endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index a5e6f641..b413f08 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -65,6 +65,7 @@ int test__thread_map(void);
 int test__llvm(void);
 void test__llvm_prepare(void);
 void test__llvm_cleanup(void);
+int test__bpf(void);
 int test__insn_x86(void);
 int test_session_topology(void);
 
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 286d3a9..578292c 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -34,6 +34,20 @@ struct bpf_prog_priv {
 	struct perf_probe_event pev;
 };
 
+struct bpf_object *
+bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
+{
+	struct bpf_object *obj;
+
+	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
+	if (!obj) {
+		pr_debug("bpf: failed to load buffer\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return obj;
+}
+
 struct bpf_object *bpf__prepare_load(const char *filename, bool source)
 {
 	struct bpf_object *obj;
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index fc6eb24..bdbd09c 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -19,6 +19,8 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
 
 #ifdef HAVE_LIBBPF_SUPPORT
 struct bpf_object *bpf__prepare_load(const char *filename, bool source);
+struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
+					    const char *name);
 
 void bpf__clear(void);
 
@@ -42,6 +44,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
 	return ERR_PTR(-ENOTSUP);
 }
 
+static inline struct bpf_object *
+bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
+					   size_t obj_buf_sz __maybe_unused)
+{
+	return ERR_PTR(-ENOTSUP);
+}
+
 static inline void bpf__clear(void) { }
 
 static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 11/22] perf probe: Reset args and nargs for probe_trace_event when failure
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (9 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 10/22] perf test: Add 'perf test BPF' Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 12/22] bpf tools: Load a program with different instances using preprocessor Wang Nan
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

When failure occures in add_probe_trace_event(), args in
probe_trace_event is incomplete. Since information in it may be used
in futher, this patch frees the allocated memory and set it to NULL
to avoid dangling pointer.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/probe-finder.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 29c43c068..5ab9cd6 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1228,6 +1228,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 
 end:
 	free(args);
+	if (ret) {
+		tev->nargs = 0;
+		zfree(&tev->args);
+	}
 	return ret;
 }
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 12/22] bpf tools: Load a program with different instances using preprocessor
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (10 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 11/22] perf probe: Reset args and nargs for probe_trace_event when failure Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 13/22] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, He Kuang, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

In this patch, caller of libbpf is able to control the loaded programs
by installing a preprocessor callback for a BPF program. With
preprocessor, different instances can be created from one BPF program.

This patch will be used by perf to generate different prologue for
different 'struct probe_trace_event' instances matched by one
'struct perf_probe_event'.

bpf_program__set_prep() is added to support this feature. Caller
should pass libbpf the number of instances should be created and a
preprocessor function which will be called when doing real loading.
The callback should return instructions arrays for each instances.

fd field in bpf_programs is replaced by instance, which has an nr field
and fds array. bpf_program__nth_fd() is introduced for read fd of
instances. Old interface bpf_program__fd() is reimplemented by
returning the first fd.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/lib/bpf/libbpf.c | 143 +++++++++++++++++++++++++++++++++++++++++++++----
 tools/lib/bpf/libbpf.h |  22 ++++++++
 2 files changed, 156 insertions(+), 9 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4252fc2..6a07b26 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -98,7 +98,11 @@ struct bpf_program {
 	} *reloc_desc;
 	int nr_reloc;
 
-	int fd;
+	struct {
+		int nr;
+		int *fds;
+	} instance;
+	bpf_program_prep_t preprocessor;
 
 	struct bpf_object *obj;
 	void *priv;
@@ -152,10 +156,24 @@ struct bpf_object {
 
 static void bpf_program__unload(struct bpf_program *prog)
 {
+	int i;
+
 	if (!prog)
 		return;
 
-	zclose(prog->fd);
+	/*
+	 * If the object is opened but the program is never loaded,
+	 * it is possible that prog->instance.nr == -1.
+	 */
+	if (prog->instance.nr > 0) {
+		for (i = 0; i < prog->instance.nr; i++)
+			zclose(prog->instance.fds[i]);
+	} else if (prog->instance.nr != -1)
+		pr_warning("Internal error: instance.nr is %d\n",
+			   prog->instance.nr);
+
+	prog->instance.nr = -1;
+	zfree(&prog->instance.fds);
 }
 
 static void bpf_program__exit(struct bpf_program *prog)
@@ -206,7 +224,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
 	memcpy(prog->insns, data,
 	       prog->insns_cnt * sizeof(struct bpf_insn));
 	prog->idx = idx;
-	prog->fd = -1;
+	prog->instance.fds = NULL;
+	prog->instance.nr = -1;
 
 	return 0;
 errout:
@@ -795,13 +814,71 @@ static int
 bpf_program__load(struct bpf_program *prog,
 		  char *license, u32 kern_version)
 {
-	int err, fd;
+	int err = 0, fd, i;
+
+	if (prog->instance.nr < 0 || !prog->instance.fds) {
+		if (prog->preprocessor) {
+			pr_warning("Internal error: can't load program '%s'\n",
+				   prog->section_name);
+			return -EINVAL;
+		}
+
+		prog->instance.fds = malloc(sizeof(int));
+		if (!prog->instance.fds) {
+			pr_warning("No enough memory for fds\n");
+			return -ENOMEM;
+		}
+		prog->instance.nr = 1;
+		prog->instance.fds[0] = -1;
+	}
+
+	if (!prog->preprocessor) {
+		if (prog->instance.nr != 1)
+			pr_warning("Program '%s' inconsistent: nr(%d) not 1\n",
+				   prog->section_name, prog->instance.nr);
 
-	err = load_program(prog->insns, prog->insns_cnt,
-			   license, kern_version, &fd);
-	if (!err)
-		prog->fd = fd;
+		err = load_program(prog->insns, prog->insns_cnt,
+				   license, kern_version, &fd);
+		if (!err)
+			prog->instance.fds[0] = fd;
+		goto out;
+	}
+
+	for (i = 0; i < prog->instance.nr; i++) {
+		struct bpf_prog_prep_result result;
+		bpf_program_prep_t preprocessor = prog->preprocessor;
+
+		bzero(&result, sizeof(result));
+		err = preprocessor(prog, i, prog->insns,
+				   prog->insns_cnt, &result);
+		if (err) {
+			pr_warning("Preprocessing %dth instance of program '%s' failed\n",
+					i, prog->section_name);
+			goto out;
+		}
+
+		if (!result.new_insn_ptr || !result.new_insn_cnt) {
+			pr_debug("Skip loading %dth instance of program '%s'\n",
+					i, prog->section_name);
+			prog->instance.fds[i] = -1;
+			continue;
+		}
+
+		err = load_program(result.new_insn_ptr,
+				   result.new_insn_cnt,
+				   license, kern_version, &fd);
+
+		if (err) {
+			pr_warning("Loading %dth instance of program '%s' failed\n",
+					i, prog->section_name);
+			goto out;
+		}
 
+		if (result.pfd)
+			*result.pfd = fd;
+		prog->instance.fds[i] = fd;
+	}
+out:
 	if (err)
 		pr_warning("failed to load program '%s'\n",
 			   prog->section_name);
@@ -1052,5 +1129,53 @@ const char *bpf_program__title(struct bpf_program *prog, bool dup)
 
 int bpf_program__fd(struct bpf_program *prog)
 {
-	return prog->fd;
+	return bpf_program__nth_fd(prog, 0);
+}
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+			  bpf_program_prep_t prep)
+{
+	int *instance_fds;
+
+	if (nr_instance <= 0 || !prep)
+		return -EINVAL;
+
+	if (prog->instance.nr > 0 || prog->instance.fds) {
+		pr_warning("Can't set pre-processor after loading\n");
+		return -EINVAL;
+	}
+
+	instance_fds = malloc(sizeof(int) * nr_instance);
+	if (!instance_fds) {
+		pr_warning("alloc memory failed for instance of fds\n");
+		return -ENOMEM;
+	}
+
+	/* fill all fd with -1 */
+	memset(instance_fds, 0xff, sizeof(int) * nr_instance);
+
+	prog->instance.nr = nr_instance;
+	prog->instance.fds = instance_fds;
+	prog->preprocessor = prep;
+	return 0;
+}
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n)
+{
+	int fd;
+
+	if (n >= prog->instance.nr || n < 0) {
+		pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+			   n, prog->section_name, prog->instance.nr);
+		return -EINVAL;
+	}
+
+	fd = prog->instance.fds[n];
+	if (fd < 0) {
+		pr_warning("%dth instance of program '%s' is invalid\n",
+			   n, prog->section_name);
+		return -ENOENT;
+	}
+
+	return fd;
 }
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index f16170c..d82b89e 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -67,6 +67,28 @@ const char *bpf_program__title(struct bpf_program *prog, bool dup);
 
 int bpf_program__fd(struct bpf_program *prog);
 
+struct bpf_insn;
+struct bpf_prog_prep_result {
+	/*
+	 * If not NULL, load new instruction array.
+	 * If set to NULL, don't load this instance.
+	 */
+	struct bpf_insn *new_insn_ptr;
+	int new_insn_cnt;
+
+	/* If not NULL, result fd is set to it */
+	int *pfd;
+};
+
+typedef int (*bpf_program_prep_t)(struct bpf_program *, int n,
+				  struct bpf_insn *, int insn_cnt,
+				  struct bpf_prog_prep_result *res);
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+			  bpf_program_prep_t prep);
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 13/22] perf tools: Add BPF_PROLOGUE config options for further patches
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (11 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 12/22] bpf tools: Load a program with different instances using preprocessor Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 14/22] perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on Wang Nan
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

If both LIBBPF and DWARF are detected, it is possible to create prologue
for eBPF programs to help them accessing kernel data. HAVE_BPF_PROLOGUE
and CONFIG_BPF_PROLOGUE is added as flags for this feature.

PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET indicates an architecture
supports converting name of a register to its offset in
'struct pt_regs'. Without this support, BPF_PROLOGUE should be turned off.

HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET is introduced as the corresponding
CFLAGS of PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/config/Makefile | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index de89ec5..6eb9a95 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -318,6 +318,18 @@ ifndef NO_LIBELF
       CFLAGS += -DHAVE_LIBBPF_SUPPORT
       $(call detected,CONFIG_LIBBPF)
     endif
+
+    ifndef NO_DWARF
+      ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+        CFLAGS += -DHAVE_BPF_PROLOGUE
+        $(call detected,CONFIG_BPF_PROLOGUE)
+      else
+        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+      endif
+    else
+      msg := $(warning DWARF support is off, BPF prologue is disabled);
+    endif
+
   endif # NO_LIBBPF
 endif # NO_LIBELF
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 14/22] perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (12 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 13/22] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 15/22] perf tools: Add prologue for BPF programs for fetching arguments Wang Nan
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, He Kuang, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, Jiri Olsa,
	Kaixu Xia, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
	Zefan Li

regs_query_register_offset() in dwarf-regs.c is required by BPF prologue.
Make it be compiled if CONFIG_BPF_PROLOGUE is on to avoid building failure
when CONFIG_BPF_PROLOGUE is on but CONFIG_DWARF is not set.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: 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: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kaixu Xia <xiakaixu@huawei.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/arch/x86/util/Build | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index ff63649..4659703 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o
 libperf-y += perf_regs.o
 
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
 
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 15/22] perf tools: Add prologue for BPF programs for fetching arguments
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (13 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 14/22] perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 16/22] perf tools: Generate prologue for BPF programs Wang Nan
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, He Kuang, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

From: He Kuang <hekuang@huawei.com>

This patch generates prologue for a BPF program which fetch arguments
for it. With this patch, the program can have arguments as follow:

 SEC("lock_page=__lock_page page->flags")
 int lock_page(struct pt_regs *ctx, int err, unsigned long flags)
 {
	 return 1;
 }

This patch passes at most 3 arguments from r3, r4 and r5. r1 is still
the ctx pointer. r2 is used to indicate the successfulness of
dereferencing.

This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack
pointer for result. Result of each arguments first store on stack:

 low address
 BPF_REG_FP - 24  ARG3
 BPF_REG_FP - 16  ARG2
 BPF_REG_FP - 8   ARG1
 BPF_REG_FP
 high address

Then loaded into r3, r4 and r5.

The output prologue for offn(...off2(off1(reg)))) should be:

     r6 <- r1			// save ctx into a callee saved register
     r7 <- fp
     r7 <- r7 - stack_offset	// pointer to result slot
     /* load r3 with the offset in pt_regs of 'reg' */
     (r7) <- r3			// make slot valid
     r3 <- r3 + off1		// prepare to read unsafe pointer
     r2 <- 8
     r1 <- r7			// result put onto stack
     call probe_read		// read unsafe pointer
     jnei r0, 0, err		// error checking
     r3 <- (r7)			// read result
     r3 <- r3 + off2		// prepare to read unsafe pointer
     r2 <- 8
     r1 <- r7
     call probe_read
     jnei r0, 0, err
     ...
     /* load r2, r3, r4 from stack */
     goto success
err:
     r2 <- 1
     /* load r3, r4, r5 with 0 */
     goto usercode
success:
     r2 <- 0
usercode:
     r1 <- r6	// restore ctx
     // original user code

If all of arguments reside in register (dereferencing is not
required), gen_prologue_fastpath() will be used to create
fast prologue:

     r3 <- (r1 + offset of reg1)
     r4 <- (r1 + offset of reg2)
     r5 <- (r1 + offset of reg3)
     r2 <- 0

P.S.

eBPF calling convention is defined as:

* r0		- return value from in-kernel function, and exit value
                  for eBPF program
* r1 - r5	- arguments from eBPF program to in-kernel function
* r6 - r9	- callee saved registers that in-kernel function will
                  preserve
* r10		- read-only frame pointer to access stack

Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/Build          |   1 +
 tools/perf/util/bpf-prologue.c | 443 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-prologue.h |  34 ++++
 3 files changed, 478 insertions(+)
 create mode 100644 tools/perf/util/bpf-prologue.c
 create mode 100644 tools/perf/util/bpf-prologue.h

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b808151..579cf84 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -87,6 +87,7 @@ libperf-y += parse-branch-options.o
 libperf-y += parse-regs-options.o
 
 libperf-$(CONFIG_LIBBPF) += bpf-loader.o
+libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.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/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
new file mode 100644
index 0000000..e4adb18
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.c
@@ -0,0 +1,443 @@
+/*
+ * bpf-prologue.c
+ *
+ * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015 Huawei Inc.
+ */
+
+#include <bpf/libbpf.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-prologue.h"
+#include "probe-finder.h"
+#include <dwarf-regs.h>
+#include <linux/filter.h>
+
+#define BPF_REG_SIZE		8
+
+#define JMP_TO_ERROR_CODE	-1
+#define JMP_TO_SUCCESS_CODE	-2
+#define JMP_TO_USER_CODE	-3
+
+struct bpf_insn_pos {
+	struct bpf_insn *begin;
+	struct bpf_insn *end;
+	struct bpf_insn *pos;
+};
+
+static inline int
+pos_get_cnt(struct bpf_insn_pos *pos)
+{
+	return pos->pos - pos->begin;
+}
+
+static int
+append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
+{
+	if (!pos->pos)
+		return -ERANGE;
+
+	if (pos->pos + 1 >= pos->end) {
+		pr_err("bpf prologue: prologue too long\n");
+		pos->pos = NULL;
+		return -ERANGE;
+	}
+
+	*(pos->pos)++ = new_insn;
+	return 0;
+}
+
+static int
+check_pos(struct bpf_insn_pos *pos)
+{
+	if (!pos->pos || pos->pos >= pos->end)
+		return -ERANGE;
+	return 0;
+}
+
+/* Give it a shorter name */
+#define ins(i, p) append_insn((i), (p))
+
+/*
+ * Give a register name (in 'reg'), generate instruction to
+ * load register into an eBPF register rd:
+ *   'ldd target_reg, offset(ctx_reg)', where:
+ * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
+ */
+static int
+gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
+		     const char *reg, int target_reg)
+{
+	int offset = regs_query_register_offset(reg);
+
+	if (offset < 0) {
+		pr_err("bpf: prologue: failed to get register %s\n",
+		       reg);
+		return -1;
+	}
+	ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
+
+	if (check_pos(pos))
+		return -ERANGE;
+	return 0;
+}
+
+/*
+ * Generate a BPF_FUNC_probe_read function call.
+ *
+ * src_base_addr_reg is a register holding base address,
+ * dst_addr_reg is a register holding dest address (on stack),
+ * result is:
+ *
+ *  *[dst_addr_reg] = *([src_base_addr_reg] + offset)
+ *
+ * Arguments of BPF_FUNC_probe_read:
+ *     ARG1: ptr to stack (dest)
+ *     ARG2: size (8)
+ *     ARG3: unsafe ptr (src)
+ */
+static int
+gen_read_mem(struct bpf_insn_pos *pos,
+	     int src_base_addr_reg,
+	     int dst_addr_reg,
+	     long offset)
+{
+	/* mov arg3, src_base_addr_reg */
+	if (src_base_addr_reg != BPF_REG_ARG3)
+		ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
+	/* add arg3, #offset */
+	if (offset)
+		ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
+
+	/* mov arg2, #reg_size */
+	ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
+
+	/* mov arg1, dst_addr_reg */
+	if (dst_addr_reg != BPF_REG_ARG1)
+		ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
+
+	/* Call probe_read  */
+	ins(BPF_EMIT_CALL(BPF_FUNC_probe_read), pos);
+	/*
+	 * Error processing: if read fail, goto error code,
+	 * will be relocated. Target should be the start of
+	 * error processing code.
+	 */
+	ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
+	    pos);
+
+	if (check_pos(pos))
+		return -ERANGE;
+	return 0;
+}
+
+/*
+ * Each arg should be bare register. Fetch and save them into argument
+ * registers (r3 - r5).
+ *
+ * BPF_REG_1 should have been initialized with pointer to
+ * 'struct pt_regs'.
+ */
+static int
+gen_prologue_fastpath(struct bpf_insn_pos *pos,
+		      struct probe_trace_arg *args, int nargs)
+{
+	int i;
+
+	for (i = 0; i < nargs; i++)
+		if (gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
+					 BPF_PROLOGUE_START_ARG_REG + i))
+			goto errout;
+
+	if (check_pos(pos))
+		goto errout;
+	return 0;
+errout:
+	return -1;
+}
+
+/*
+ * Slow path:
+ *   At least one argument has the form of 'offset($rx)'.
+ *
+ * Following code first stores them into stack, then loads all of then
+ * to r2 - r5.
+ * Before final loading, the final result should be:
+ *
+ * low address
+ * BPF_REG_FP - 24  ARG3
+ * BPF_REG_FP - 16  ARG2
+ * BPF_REG_FP - 8   ARG1
+ * BPF_REG_FP
+ * high address
+ *
+ * For each argument (described as: offn(...off2(off1(reg)))),
+ * generates following code:
+ *
+ *  r7 <- fp
+ *  r7 <- r7 - stack_offset  // Ideal code should initialize r7 using
+ *                           // fp before generating args. However,
+ *                           // eBPF won't regard r7 as stack pointer
+ *                           // if it is generated by minus 8 from
+ *                           // another stack pointer except fp.
+ *                           // This is why we have to set r7
+ *                           // to fp for each variable.
+ *  r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
+ *  (r7) <- r3       // skip following instructions for bare reg
+ *  r3 <- r3 + off1  . // skip if off1 == 0
+ *  r2 <- 8           \
+ *  r1 <- r7           |-> generated by gen_read_mem()
+ *  call probe_read    /
+ *  jnei r0, 0, err  ./
+ *  r3 <- (r7)
+ *  r3 <- r3 + off2  . // skip if off2 == 0
+ *  r2 <- 8           \  // r2 may be broken by probe_read, so set again
+ *  r1 <- r7           |-> generated by gen_read_mem()
+ *  call probe_read    /
+ *  jnei r0, 0, err  ./
+ *  ...
+ */
+static int
+gen_prologue_slowpath(struct bpf_insn_pos *pos,
+		      struct probe_trace_arg *args, int nargs)
+{
+	int i;
+
+	for (i = 0; i < nargs; i++) {
+		struct probe_trace_arg *arg = &args[i];
+		const char *reg = arg->value;
+		struct probe_trace_arg_ref *ref = NULL;
+		int stack_offset = (i + 1) * -8;
+
+		pr_debug("prologue: fetch arg %d, base reg is %s\n",
+			 i, reg);
+
+		/* value of base register is stored into ARG3 */
+		if (gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
+					 BPF_REG_ARG3)) {
+			pr_err("prologue: failed to get offset of register %s\n",
+			       reg);
+			goto errout;
+		}
+
+		/* Make r7 the stack pointer. */
+		ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
+		/* r7 += -8 */
+		ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
+		/*
+		 * Store r3 (base register) onto stack
+		 * Ensure fp[offset] is set.
+		 * fp is the only valid base register when storing
+		 * into stack. We are not allowed to use r7 as base
+		 * register here.
+		 */
+		ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
+				stack_offset), pos);
+
+		ref = arg->ref;
+		while (ref) {
+			pr_debug("prologue: arg %d: offset %ld\n",
+				 i, ref->offset);
+			if (gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
+					 ref->offset)) {
+				pr_err("prologue: failed to generate probe_read function call\n");
+				goto errout;
+			}
+
+			ref = ref->next;
+			/*
+			 * Load previous result into ARG3. Use
+			 * BPF_REG_FP instead of r7 because verifier
+			 * allows FP based addressing only.
+			 */
+			if (ref)
+				ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
+						BPF_REG_FP, stack_offset), pos);
+		}
+	}
+
+	/* Final pass: read to registers */
+	for (i = 0; i < nargs; i++)
+		ins(BPF_LDX_MEM(BPF_DW, BPF_PROLOGUE_START_ARG_REG + i,
+				BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
+
+	ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
+
+	if (check_pos(pos))
+		goto errout;
+	return 0;
+errout:
+	return -1;
+}
+
+static int
+prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
+	    struct bpf_insn *success_code, struct bpf_insn *user_code)
+{
+	struct bpf_insn *insn;
+
+	if (check_pos(pos))
+		return -ERANGE;
+
+	for (insn = pos->begin; insn < pos->pos; insn++) {
+		u8 class = BPF_CLASS(insn->code);
+		u8 opcode;
+
+		if (class != BPF_JMP)
+			continue;
+		opcode = BPF_OP(insn->code);
+		if (opcode == BPF_CALL)
+			continue;
+
+		switch (insn->off) {
+		case JMP_TO_ERROR_CODE:
+			insn->off = error_code - (insn + 1);
+			break;
+		case JMP_TO_SUCCESS_CODE:
+			insn->off = success_code - (insn + 1);
+			break;
+		case JMP_TO_USER_CODE:
+			insn->off = user_code - (insn + 1);
+			break;
+		default:
+			pr_err("bpf prologue: internal error: relocation failed\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+		      struct bpf_insn *new_prog, size_t *new_cnt,
+		      size_t cnt_space)
+{
+	struct bpf_insn *success_code = NULL;
+	struct bpf_insn *error_code = NULL;
+	struct bpf_insn *user_code = NULL;
+	struct bpf_insn_pos pos;
+	bool fastpath = true;
+	int i;
+
+	if (!new_prog || !new_cnt)
+		return -EINVAL;
+
+	pos.begin = new_prog;
+	pos.end = new_prog + cnt_space;
+	pos.pos = new_prog;
+
+	if (!nargs) {
+		ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
+		    &pos);
+
+		if (check_pos(&pos))
+			goto errout;
+
+		*new_cnt = pos_get_cnt(&pos);
+		return 0;
+	}
+
+	if (nargs > BPF_PROLOGUE_MAX_ARGS)
+		nargs = BPF_PROLOGUE_MAX_ARGS;
+	if (cnt_space > BPF_MAXINSNS)
+		cnt_space = BPF_MAXINSNS;
+
+	/* First pass: validation */
+	for (i = 0; i < nargs; i++) {
+		struct probe_trace_arg_ref *ref = args[i].ref;
+
+		if (args[i].value[0] == '@') {
+			/* TODO: fetch global variable */
+			pr_err("bpf: prologue: global %s%+ld not support\n",
+				args[i].value, ref ? ref->offset : 0);
+			return -ENOTSUP;
+		}
+
+		while (ref) {
+			/* fastpath is true if all args has ref == NULL */
+			fastpath = false;
+
+			/*
+			 * Instruction encodes immediate value using
+			 * s32, ref->offset is long. On systems which
+			 * can't fill long in s32, refuse to process if
+			 * ref->offset too large (or small).
+			 */
+#ifdef __LP64__
+#define OFFSET_MAX	((1LL << 31) - 1)
+#define OFFSET_MIN	((1LL << 31) * -1)
+			if (ref->offset > OFFSET_MAX ||
+					ref->offset < OFFSET_MIN) {
+				pr_err("bpf: prologue: offset out of bound: %ld\n",
+				       ref->offset);
+				return -E2BIG;
+			}
+#endif
+			ref = ref->next;
+		}
+	}
+	pr_debug("prologue: pass validation\n");
+
+	if (fastpath) {
+		/* If all variables are registers... */
+		pr_debug("prologue: fast path\n");
+		if (gen_prologue_fastpath(&pos, args, nargs))
+			goto errout;
+	} else {
+		pr_debug("prologue: slow path\n");
+
+		/* Initialization: move ctx to a callee saved register. */
+		ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
+
+		if (gen_prologue_slowpath(&pos, args, nargs))
+			goto errout;
+		/*
+		 * start of ERROR_CODE (only slow pass needs error code)
+		 *   mov r2 <- 1
+		 *   goto usercode
+		 */
+		error_code = pos.pos;
+		ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
+		    &pos);
+
+		for (i = 0; i < nargs; i++)
+			ins(BPF_ALU64_IMM(BPF_MOV,
+					  BPF_PROLOGUE_START_ARG_REG + i,
+					  0),
+			    &pos);
+		ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
+				&pos);
+	}
+
+	/*
+	 * start of SUCCESS_CODE:
+	 *   mov r2 <- 0
+	 *   goto usercode  // skip
+	 */
+	success_code = pos.pos;
+	ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
+
+	/*
+	 * start of USER_CODE:
+	 *   Restore ctx to r1
+	 */
+	user_code = pos.pos;
+	if (!fastpath) {
+		/*
+		 * Only slow path needs restoring of ctx. In fast path,
+		 * register are loaded directly from r1.
+		 */
+		ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
+		if (prologue_relocate(&pos, error_code, success_code,
+				      user_code))
+			goto errout;
+	}
+
+	if (check_pos(&pos))
+		goto errout;
+
+	*new_cnt = pos_get_cnt(&pos);
+	return 0;
+errout:
+	return -ERANGE;
+}
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
new file mode 100644
index 0000000..f1e4c5d
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015, He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ */
+#ifndef __BPF_PROLOGUE_H
+#define __BPF_PROLOGUE_H
+
+#include <linux/compiler.h>
+#include <linux/filter.h>
+#include "probe-event.h"
+
+#define BPF_PROLOGUE_MAX_ARGS 3
+#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3
+#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2
+
+#ifdef HAVE_BPF_PROLOGUE
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+		      struct bpf_insn *new_prog, size_t *new_cnt,
+		      size_t cnt_space);
+#else
+static inline int
+bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
+		  int nargs __maybe_unused,
+		  struct bpf_insn *new_prog __maybe_unused,
+		  size_t *new_cnt,
+		  size_t cnt_space __maybe_unused)
+{
+	if (!new_cnt)
+		return -EINVAL;
+	*new_cnt = 0;
+	return 0;
+}
+#endif
+#endif /* __BPF_PROLOGUE_H */
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 16/22] perf tools: Generate prologue for BPF programs
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (14 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 15/22] perf tools: Add prologue for BPF programs for fetching arguments Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 17/22] perf tools: Use same BPF program if arguments are identical Wang Nan
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch generates prologue for each 'struct probe_trace_event' for
fetching arguments for BPF programs.

After bpf__probe(), iterate over each programs to check whether
prologue is required. If none of 'struct perf_probe_event' a program
will attach to has at least one argument, simply skip preprocessor
hooking. For those who prologue is required, calls bpf__gen_prologue()
and paste original instruction after prologue.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c | 120 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 578292c..09e0916 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -5,11 +5,14 @@
  * Copyright (C) 2015 Huawei Inc.
  */
 
+#include <linux/bpf.h>
 #include <bpf/libbpf.h>
 #include <linux/err.h>
 #include "perf.h"
 #include "debug.h"
 #include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "llvm-utils.h"
 #include "probe-event.h"
 #include "probe-finder.h" // for MAX_PROBES
 #include "llvm-utils.h"
@@ -32,6 +35,8 @@ DEFINE_PRINT_FN(debug, 1)
 
 struct bpf_prog_priv {
 	struct perf_probe_event pev;
+	bool need_prologue;
+	struct bpf_insn *insns_buf;
 };
 
 struct bpf_object *
@@ -98,6 +103,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
 	struct bpf_prog_priv *priv = _priv;
 
 	cleanup_perf_probe_events(&priv->pev, 1);
+	zfree(&priv->insns_buf);
 	free(priv);
 }
 
@@ -189,6 +195,102 @@ static int bpf__prepare_probe(void)
 	return err;
 }
 
+static int
+preproc_gen_prologue(struct bpf_program *prog, int n,
+		     struct bpf_insn *orig_insns, int orig_insns_cnt,
+		     struct bpf_prog_prep_result *res)
+{
+	struct probe_trace_event *tev;
+	struct perf_probe_event *pev;
+	struct bpf_prog_priv *priv;
+	struct bpf_insn *buf;
+	size_t prologue_cnt = 0;
+	int err;
+
+	err = bpf_program__get_private(prog, (void **)&priv);
+	if (err || !priv)
+		goto errout;
+
+	pev = &priv->pev;
+
+	if (n < 0 || n >= pev->ntevs)
+		goto errout;
+
+	tev = &pev->tevs[n];
+
+	buf = priv->insns_buf;
+	err = bpf__gen_prologue(tev->args, tev->nargs,
+				buf, &prologue_cnt,
+				BPF_MAXINSNS - orig_insns_cnt);
+	if (err) {
+		const char *title;
+
+		title = bpf_program__title(prog, false);
+		if (!title)
+			title = "[unknown]";
+
+		pr_debug("Failed to generate prologue for program %s\n",
+			 title);
+		return err;
+	}
+
+	memcpy(&buf[prologue_cnt], orig_insns,
+	       sizeof(struct bpf_insn) * orig_insns_cnt);
+
+	res->new_insn_ptr = buf;
+	res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
+	res->pfd = NULL;
+	return 0;
+
+errout:
+	pr_debug("Internal error in preproc_gen_prologue\n");
+	return -EINVAL;
+}
+
+static int hook_load_preprocessor(struct bpf_program *prog)
+{
+	struct perf_probe_event *pev;
+	struct bpf_prog_priv *priv;
+	bool need_prologue = false;
+	int err, i;
+
+	err = bpf_program__get_private(prog, (void **)&priv);
+	if (err || !priv) {
+		pr_debug("Internal error when hook preprocessor\n");
+		return -EINVAL;
+	}
+
+	pev = &priv->pev;
+	for (i = 0; i < pev->ntevs; i++) {
+		struct probe_trace_event *tev = &pev->tevs[i];
+
+		if (tev->nargs > 0) {
+			need_prologue = true;
+			break;
+		}
+	}
+
+	/*
+	 * Since all tev doesn't have argument, we don't need generate
+	 * prologue.
+	 */
+	if (!need_prologue) {
+		priv->need_prologue = false;
+		return 0;
+	}
+
+	priv->need_prologue = true;
+	priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
+	if (!priv->insns_buf) {
+		pr_debug("No enough memory: alloc insns_buf failed\n");
+		return -ENOMEM;
+	}
+
+	err = bpf_program__set_prep(prog, pev->ntevs,
+				    preproc_gen_prologue);
+	return err;
+}
+
 int bpf__probe(struct bpf_object *obj)
 {
 	int err = 0;
@@ -223,6 +325,18 @@ int bpf__probe(struct bpf_object *obj)
 			pr_debug("bpf_probe: failed to apply perf probe events");
 			goto out;
 		}
+
+		/*
+		 * After probing, let's consider prologue, which
+		 * adds program fetcher to BPF programs.
+		 *
+		 * hook_load_preprocessorr() hooks pre-processor
+		 * to bpf_program, let it generate prologue
+		 * dynamically during loading.
+		 */
+		err = hook_load_preprocessor(prog);
+		if (err)
+			goto out;
 	}
 out:
 	return err < 0 ? err : 0;
@@ -305,7 +419,11 @@ int bpf__foreach_tev(struct bpf_object *obj,
 		for (i = 0; i < pev->ntevs; i++) {
 			tev = &pev->tevs[i];
 
-			fd = bpf_program__fd(prog);
+			if (priv->need_prologue)
+				fd = bpf_program__nth_fd(prog, i);
+			else
+				fd = bpf_program__fd(prog);
+
 			if (fd < 0) {
 				pr_debug("bpf: failed to get file descriptor\n");
 				return fd;
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 17/22] perf tools: Use same BPF program if arguments are identical
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (15 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 16/22] perf tools: Generate prologue for BPF programs Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 18/22] perf record: Support custom vmlinux path Wang Nan
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch allows creating only one BPF program for different
'probe_trace_event'(tev) generated by one 'perf_probe_event'(pev), if
their prologues are identical.

This is done by comparing argument list of different tev, and maps type
of prologue and tev using a mapping array. This patch utilizes qsort to
sort tevs. After sorting, tevs with identical argument list will be
grouped together.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c | 133 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 126 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 09e0916..8e9c882 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -37,6 +37,8 @@ struct bpf_prog_priv {
 	struct perf_probe_event pev;
 	bool need_prologue;
 	struct bpf_insn *insns_buf;
+	int nr_types;
+	int *type_mapping;
 };
 
 struct bpf_object *
@@ -104,6 +106,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
 
 	cleanup_perf_probe_events(&priv->pev, 1);
 	zfree(&priv->insns_buf);
+	zfree(&priv->type_mapping);
 	free(priv);
 }
 
@@ -205,7 +208,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
 	struct bpf_prog_priv *priv;
 	struct bpf_insn *buf;
 	size_t prologue_cnt = 0;
-	int err;
+	int i, err;
 
 	err = bpf_program__get_private(prog, (void **)&priv);
 	if (err || !priv)
@@ -213,10 +216,20 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
 
 	pev = &priv->pev;
 
-	if (n < 0 || n >= pev->ntevs)
+	if (n < 0 || n >= priv->nr_types)
 		goto errout;
 
-	tev = &pev->tevs[n];
+	/* Find a tev belongs to that type */
+	for (i = 0; i < pev->ntevs; i++)
+		if (priv->type_mapping[i] == n)
+			break;
+
+	if (i >= pev->ntevs) {
+		pr_debug("Internal error: prologue type %d not found\n", n);
+		return -ENOENT;
+	}
+
+	tev = &pev->tevs[i];
 
 	buf = priv->insns_buf;
 	err = bpf__gen_prologue(tev->args, tev->nargs,
@@ -247,6 +260,98 @@ errout:
 	return -EINVAL;
 }
 
+/*
+ * compare_tev_args is reflexive, transitive and antisymmetric.
+ * I can show that but this margin is too narrow to contain.
+ */
+static int compare_tev_args(const void *ptev1, const void *ptev2)
+{
+	int i, ret;
+	const struct probe_trace_event *tev1 =
+		*(const struct probe_trace_event **)ptev1;
+	const struct probe_trace_event *tev2 =
+		*(const struct probe_trace_event **)ptev2;
+
+	ret = tev2->nargs - tev1->nargs;
+	if (ret)
+		return ret;
+
+	for (i = 0; i < tev1->nargs; i++) {
+		struct probe_trace_arg *arg1, *arg2;
+		struct probe_trace_arg_ref *ref1, *ref2;
+
+		arg1 = &tev1->args[i];
+		arg2 = &tev2->args[i];
+
+		ret = strcmp(arg1->value, arg2->value);
+		if (ret)
+			return ret;
+
+		ref1 = arg1->ref;
+		ref2 = arg2->ref;
+
+		while (ref1 && ref2) {
+			ret = ref2->offset - ref1->offset;
+			if (ret)
+				return ret;
+
+			ref1 = ref1->next;
+			ref2 = ref2->next;
+		}
+
+		if (ref1 || ref2)
+			return ref2 ? 1 : -1;
+	}
+
+	return 0;
+}
+
+static int map_prologue(struct perf_probe_event *pev, int *mapping,
+			int *nr_types)
+{
+	int i, type = 0;
+	struct {
+		struct probe_trace_event *tev;
+		int idx;
+	} *stevs;
+	size_t array_sz = sizeof(*stevs) * pev->ntevs;
+
+	stevs = malloc(array_sz);
+	if (!stevs) {
+		pr_debug("No ehough memory: alloc stevs failed\n");
+		return -ENOMEM;
+	}
+
+	pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
+	for (i = 0; i < pev->ntevs; i++) {
+		stevs[i].tev = &pev->tevs[i];
+		stevs[i].idx = i;
+	}
+	qsort(stevs, pev->ntevs, sizeof(*stevs),
+	      compare_tev_args);
+
+	for (i = 0; i < pev->ntevs; i++) {
+		if (i == 0) {
+			mapping[stevs[i].idx] = type;
+			pr_debug("mapping[%d]=%d\n", stevs[i].idx,
+				 type);
+			continue;
+		}
+
+		if (compare_tev_args(stevs + i, stevs + i - 1) == 0)
+			mapping[stevs[i].idx] = type;
+		else
+			mapping[stevs[i].idx] = ++type;
+
+		pr_debug("mapping[%d]=%d\n", stevs[i].idx,
+			 mapping[stevs[i].idx]);
+	}
+	free(stevs);
+	*nr_types = type + 1;
+
+	return 0;
+}
+
 static int hook_load_preprocessor(struct bpf_program *prog)
 {
 	struct perf_probe_event *pev;
@@ -286,7 +391,19 @@ static int hook_load_preprocessor(struct bpf_program *prog)
 		return -ENOMEM;
 	}
 
-	err = bpf_program__set_prep(prog, pev->ntevs,
+	priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
+	if (!priv->type_mapping) {
+		pr_debug("No enough memory: alloc type_mapping failed\n");
+		return -ENOMEM;
+	}
+	memset(priv->type_mapping, 0xff,
+	       sizeof(int) * pev->ntevs);
+
+	err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
+	if (err)
+		return err;
+
+	err = bpf_program__set_prep(prog, priv->nr_types,
 				    preproc_gen_prologue);
 	return err;
 }
@@ -419,9 +536,11 @@ int bpf__foreach_tev(struct bpf_object *obj,
 		for (i = 0; i < pev->ntevs; i++) {
 			tev = &pev->tevs[i];
 
-			if (priv->need_prologue)
-				fd = bpf_program__nth_fd(prog, i);
-			else
+			if (priv->need_prologue) {
+				int type = priv->type_mapping[i];
+
+				fd = bpf_program__nth_fd(prog, type);
+			} else
 				fd = bpf_program__fd(prog);
 
 			if (fd < 0) {
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 18/22] perf record: Support custom vmlinux path
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (16 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 17/22] perf tools: Use same BPF program if arguments are identical Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 19/22] perf tools: Allow BPF program attach to uprobe events Wang Nan
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, He Kuang, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

From: He Kuang <hekuang@huawei.com>

Make perf-record command support --vmlinux option if BPF_PROLOGUE is on.

'perf record' needs vmlinux as the source of DWARF info to generate
prologue for BPF programs, so path of vmlinux should be specified.

Short name 'k' has been taken by 'clockid'. This patch skips the short
option name and use '--vmlinux' for vmlinux path.

Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/builtin-record.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ea3eef6..a0c8ef8 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1102,6 +1102,10 @@ struct option __record_options[] = {
 		   "clang binary to use for compiling BPF scriptlets"),
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 		   "options passed to clang when compiling BPF scriptlets"),
+#ifdef HAVE_BPF_PROLOGUE
+	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
+		   "file", "vmlinux pathname"),
+#endif
 #endif
 	OPT_END()
 };
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 19/22] perf tools: Allow BPF program attach to uprobe events
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (17 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 18/22] perf record: Support custom vmlinux path Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 20/22] perf test: Enforce LLVM test, add kbuild test Wang Nan
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Paul Mackerras,
	Peter Zijlstra, Zefan Li

This patch appends new syntax to BPF object section name to support
probing at uprobe event. Now we can use BPF program like this:

 SEC(
 "target=/lib64/libc.so.6\n"
 "libcwrite=__write"
 )
 int libcwrite(void *ctx)
 {
     return 1;
 }

Where, in section name of a program, before the main config string,
we can use 'key=value' style options. Now the only option key "target"
is for uprobe probing.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: 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: He Kuang <hekuang@huawei.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: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/bpf-loader.c | 86 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 80 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 8e9c882..9cc2822 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -111,6 +111,84 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
 }
 
 static int
+do_config(const char *key, const char *value,
+	  struct perf_probe_event *pev)
+{
+	pr_debug("config bpf program: %s=%s\n", key, value);
+	if (strcmp(key, "target") == 0) {
+		pev->uprobes = true;
+		pev->target = strdup(value);
+		return 0;
+	}
+
+	pr_warning("BPF: WARNING: invalid config option in object: %s=%s\n",
+		   key, value);
+	pr_warning("\tHint: Currently only valid option is 'target=<file>'\n");
+	return 0;
+}
+
+static const char *
+parse_config_kvpair(const char *config_str, struct perf_probe_event *pev)
+{
+	char *text = strdup(config_str);
+	char *sep, *line;
+	const char *main_str = NULL;
+	int err = 0;
+
+	if (!text) {
+		pr_debug("No enough memory: dup config_str failed\n");
+		return NULL;
+	}
+
+	line = text;
+	while ((sep = strchr(line, '\n'))) {
+		char *equ;
+
+		*sep = '\0';
+		equ = strchr(line, '=');
+		if (!equ) {
+			pr_warning("WARNING: invalid config in BPF object: %s\n",
+				   line);
+			pr_warning("\tShould be 'key=value'.\n");
+			goto nextline;
+		}
+		*equ = '\0';
+
+		err = do_config(line, equ + 1, pev);
+		if (err)
+			break;
+nextline:
+		line = sep + 1;
+	}
+
+	if (!err)
+		main_str = config_str + (line - text);
+	free(text);
+
+	return main_str;
+}
+
+static int
+parse_config(const char *config_str, struct perf_probe_event *pev)
+{
+	const char *main_str;
+	int err;
+
+	main_str = parse_config_kvpair(config_str, pev);
+	if (!main_str)
+		return -EINVAL;
+
+	err = parse_perf_probe_command(main_str, pev);
+	if (err < 0) {
+		pr_debug("bpf: '%s' is not a valid config string\n",
+			 config_str);
+		/* parse failed, don't need clear pev. */
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
 config_bpf_program(struct bpf_program *prog)
 {
 	struct perf_probe_event *pev = NULL;
@@ -132,13 +210,9 @@ config_bpf_program(struct bpf_program *prog)
 	pev = &priv->pev;
 
 	pr_debug("bpf: config program '%s'\n", config_str);
-	err = parse_perf_probe_command(config_str, pev);
-	if (err < 0) {
-		pr_debug("bpf: '%s' is not a valid config string\n",
-			 config_str);
-		err = -EINVAL;
+	err = parse_config(config_str, pev);
+	if (err)
 		goto errout;
-	}
 
 	if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
 		pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 20/22] perf test: Enforce LLVM test, add kbuild test
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (18 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 19/22] perf tools: Allow BPF program attach to uprobe events Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 21/22] perf test: Test BPF prologue Wang Nan
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	Zefan Li

This patch enforces existing LLVM test, makes it compile more than one
BPF source file. The compiled results are stored, can be used for other
testcases. Except the first testcase (named LLVM_TESTCASE_BASE), failures
of other test cases are not considered as failure of the whole test.

Adds a kbuild testcase to check whether kernel headers can be correctly
found.

For example:

 # perf test LLVM

   38: Test LLVM searching and compiling                        : (llvm.kbuild-dir can be fixed) Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: 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: He Kuang <hekuang@huawei.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
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/tests/Build                    |  11 ++-
 tools/perf/tests/bpf-script-example.c     |   4 +
 tools/perf/tests/bpf-script-test-kbuild.c |  21 ++++
 tools/perf/tests/bpf.c                    |   3 +-
 tools/perf/tests/llvm.c                   | 154 ++++++++++++++++++++++--------
 tools/perf/tests/llvm.h                   |  10 +-
 6 files changed, 156 insertions(+), 47 deletions(-)
 create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 5cfb420..2bd5f37 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,17 +32,24 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
-perf-y += llvm.o llvm-src.o
+perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
 perf-y += bpf.o
 perf-y += topology.o
 
-$(OUTPUT)tests/llvm-src.c: tests/bpf-script-example.c
+$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
 	$(call rule_mkdir)
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo 'const char test_llvm__bpf_prog[] =' >> $@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 
+$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c
+	$(call rule_mkdir)
+	$(Q)echo '#include <tests/llvm.h>' > $@
+	$(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 ifdef CONFIG_AUXTRACE
 perf-$(CONFIG_X86) += insn-x86.o
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
index 410a70b..0ec9c2c 100644
--- a/tools/perf/tests/bpf-script-example.c
+++ b/tools/perf/tests/bpf-script-example.c
@@ -1,3 +1,7 @@
+/*
+ * bpf-script-example.c
+ * Test basic LLVM building
+ */
 #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'
diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c
new file mode 100644
index 0000000..a11f589
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-kbuild.c
@@ -0,0 +1,21 @@
+/*
+ * bpf-script-test-kbuild.c
+ * Test include from kernel header
+ */
+#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 SEC(NAME) __attribute__((section(NAME), used))
+
+#include <uapi/linux/fs.h>
+#include <uapi/asm/ptrace.h>
+
+SEC("func=vfs_llseek")
+int bpf_func__vfs_llseek(struct pt_regs *ctx)
+{
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index d7cdc84..4dd701b 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -140,7 +140,8 @@ int test__bpf(void)
 		return TEST_SKIP;
 	}
 
-	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz);
+	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, LLVM_TESTCASE_BASE);
+
 	if (!obj_buf || !obj_buf_sz) {
 		if (verbose == 0)
 			fprintf(stderr, " (fix 'perf test LLVM' first)");
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index fd5fdb0..75cd99f 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -9,6 +9,22 @@
 #include "debug.h"
 #include "llvm.h"
 
+#define SHARED_BUF_INIT_SIZE	(1 << 20)
+struct llvm_testcase {
+	const char *source;
+	const char *errmsg;
+	struct test_llvm__bpf_result *result;
+	bool tried;
+} llvm_testcases[NR_LLVM_TESTCASES + 1] = {
+	[LLVM_TESTCASE_BASE]	= {.source = test_llvm__bpf_prog,
+				   .errmsg = "Basic LLVM compiling failed",
+				   .tried = false},
+	[LLVM_TESTCASE_KBUILD]	= {.source = test_llvm__bpf_test_kbuild_prog,
+				   .errmsg = "llvm.kbuild-dir can be fixed",
+				   .tried = false},
+	{.source = NULL}
+};
+
 static int perf_config_cb(const char *var, const char *val,
 			  void *arg __maybe_unused)
 {
@@ -36,7 +52,7 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
 #endif
 
 static char *
-compose_source(void)
+compose_source(const char *raw_source)
 {
 	struct utsname utsname;
 	int version, patchlevel, sublevel, err;
@@ -56,25 +72,27 @@ compose_source(void)
 
 	version_code = (version << 16) + (patchlevel << 8) + sublevel;
 	err = asprintf(&code, "#define LINUX_VERSION_CODE 0x%08lx;\n%s",
-		       version_code, test_llvm__bpf_prog);
+		       version_code, raw_source);
 	if (err < 0)
 		return NULL;
 
 	return code;
 }
 
-#define SHARED_BUF_INIT_SIZE	(1 << 20)
-struct test_llvm__bpf_result *p_test_llvm__bpf_result;
 
-int test__llvm(void)
+static int __test__llvm(int i)
 {
-	char *tmpl_new, *clang_opt_new;
 	void *obj_buf;
 	size_t obj_buf_sz;
 	int err, old_verbose;
-	char *source;
+	const char *tmpl_old, *clang_opt_old;
+	char *tmpl_new, *clang_opt_new, *source;
+	const char *raw_source = llvm_testcases[i].source;
+	struct test_llvm__bpf_result *result = llvm_testcases[i].result;
 
 	perf_config(perf_config_cb, NULL);
+	clang_opt_old = llvm_param.clang_opt;
+	tmpl_old = llvm_param.clang_bpf_cmd_template;
 
 	/*
 	 * Skip this test if user's .perfconfig doesn't set [llvm] section
@@ -99,15 +117,17 @@ int test__llvm(void)
 	if (!llvm_param.clang_opt)
 		llvm_param.clang_opt = strdup("");
 
-	source = compose_source();
+	source = compose_source(raw_source);
 	if (!source) {
 		pr_err("Failed to compose source code\n");
 		return -1;
 	}
 
 	/* Quote __EOF__ so strings in source won't be expanded by shell */
-	err = asprintf(&tmpl_new, "cat << '__EOF__' | %s\n%s\n__EOF__\n",
-		       llvm_param.clang_bpf_cmd_template, source);
+	err = asprintf(&tmpl_new, "cat << '__EOF__' | %s %s \n%s\n__EOF__\n",
+		       llvm_param.clang_bpf_cmd_template,
+		       !old_verbose ? "2>/dev/null" : "",
+		       source);
 	free(source);
 	source = NULL;
 	if (err < 0) {
@@ -123,73 +143,123 @@ int test__llvm(void)
 	llvm_param.clang_opt = clang_opt_new;
 	err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
 
+	free((void *)llvm_param.clang_bpf_cmd_template);
+	free((void *)llvm_param.clang_opt);
+	llvm_param.clang_bpf_cmd_template = tmpl_old;
+	llvm_param.clang_opt = clang_opt_old;
+
 	verbose = old_verbose;
-	if (err) {
-		if (!verbose)
-			fprintf(stderr, " (use -v to see error message)");
+	if (err)
 		return -1;
-	}
 
 	err = test__bpf_parsing(obj_buf, obj_buf_sz);
-	if (!err && p_test_llvm__bpf_result) {
+	if (!err && result) {
 		if (obj_buf_sz > SHARED_BUF_INIT_SIZE) {
 			pr_err("Resulting object too large\n");
 		} else {
-			p_test_llvm__bpf_result->size = obj_buf_sz;
-			memcpy(p_test_llvm__bpf_result->object,
-			       obj_buf, obj_buf_sz);
+			result->size = obj_buf_sz;
+			memcpy(result->object, obj_buf, obj_buf_sz);
 		}
 	}
 	free(obj_buf);
 	return err;
 }
 
+int test__llvm(void)
+{
+	int i, ret;
+
+	for (i = 0; llvm_testcases[i].source; i++) {
+		ret = __test__llvm(i);
+		if (i == 0 && ret) {
+			/*
+			 * First testcase tests basic LLVM compiling. If it
+			 * fails, no need to check others.
+			 */
+			if (!verbose)
+				fprintf(stderr, " (use -v to see error message)");
+			return ret;
+		} else if (ret) {
+			if (!verbose && llvm_testcases[i].errmsg)
+				fprintf(stderr, " (%s)", llvm_testcases[i].errmsg);
+			return 0;
+		}
+	}
+	return 0;
+}
+
 void test__llvm_prepare(void)
 {
-	p_test_llvm__bpf_result = mmap(NULL, SHARED_BUF_INIT_SIZE,
-				       PROT_READ | PROT_WRITE,
-				       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-	if (!p_test_llvm__bpf_result)
-		return;
-	memset((void *)p_test_llvm__bpf_result, '\0', SHARED_BUF_INIT_SIZE);
+	int i;
+
+	for (i = 0; llvm_testcases[i].source; i++) {
+		struct test_llvm__bpf_result *result;
+
+		result = mmap(NULL, SHARED_BUF_INIT_SIZE,
+			      PROT_READ | PROT_WRITE,
+			      MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+		if (!result)
+			return;
+		memset((void *)result, '\0', SHARED_BUF_INIT_SIZE);
+
+		llvm_testcases[i].result = result;
+	}
 }
 
 void test__llvm_cleanup(void)
 {
-	unsigned long boundary, buf_end;
+	int i;
 
-	if (!p_test_llvm__bpf_result)
-		return;
-	if (p_test_llvm__bpf_result->size == 0) {
-		munmap((void *)p_test_llvm__bpf_result, SHARED_BUF_INIT_SIZE);
-		p_test_llvm__bpf_result = NULL;
-		return;
-	}
+	for (i = 0; llvm_testcases[i].source; i++) {
+		struct test_llvm__bpf_result *result;
+		unsigned long boundary, buf_end;
 
-	buf_end = (unsigned long)p_test_llvm__bpf_result + SHARED_BUF_INIT_SIZE;
+		result = llvm_testcases[i].result;
+		llvm_testcases[i].tried = true;
 
-	boundary = (unsigned long)(p_test_llvm__bpf_result);
-	boundary += p_test_llvm__bpf_result->size;
-	boundary = (boundary + (page_size - 1)) &
+		if (!result)
+			continue;
+
+		if (result->size == 0) {
+			munmap((void *)result, SHARED_BUF_INIT_SIZE);
+			result = NULL;
+			llvm_testcases[i].result = NULL;
+			continue;
+		}
+
+		buf_end = (unsigned long)result + SHARED_BUF_INIT_SIZE;
+
+		boundary = (unsigned long)(result);
+		boundary += result->size;
+		boundary = (boundary + (page_size - 1)) &
 			(~((unsigned long)page_size - 1));
-	munmap((void *)boundary, buf_end - boundary);
+		munmap((void *)boundary, buf_end - boundary);
+	}
 }
 
 void
-test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz)
+test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, int index)
 {
+	struct test_llvm__bpf_result *result;
+
 	*p_obj_buf = NULL;
 	*p_obj_buf_sz = 0;
 
-	if (!p_test_llvm__bpf_result) {
+	if (index > NR_LLVM_TESTCASES)
+		return;
+
+	result = llvm_testcases[index].result;
+
+	if (!result && !llvm_testcases[index].tried) {
 		test__llvm_prepare();
 		test__llvm();
 		test__llvm_cleanup();
 	}
 
-	if (!p_test_llvm__bpf_result)
+	result = llvm_testcases[index].result;
+	if (!result)
 		return;
 
-	*p_obj_buf = p_test_llvm__bpf_result->object;
-	*p_obj_buf_sz = p_test_llvm__bpf_result->size;
+	*p_obj_buf = result->object;
+	*p_obj_buf_sz = result->size;
 }
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 2fd7ed6..78ec01d 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -8,8 +8,14 @@ struct test_llvm__bpf_result {
 	char object[];
 };
 
-extern struct test_llvm__bpf_result *p_test_llvm__bpf_result;
 extern const char test_llvm__bpf_prog[];
-void test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz);
+extern const char test_llvm__bpf_test_kbuild_prog[];
+
+enum test_llvm__testcase {
+	LLVM_TESTCASE_BASE,
+	LLVM_TESTCASE_KBUILD,
+	NR_LLVM_TESTCASES,
+};
+void test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, int index);
 
 #endif
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 21/22] perf test: Test BPF prologue
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (19 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 20/22] perf test: Enforce LLVM test, add kbuild test Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 11:22 ` [PATCH 22/22] perf probe: Fix module probing with shortname Wang Nan
  2015-09-23 13:46 ` [GIT PULL 00/22] perf tools: filtering events using eBPF programs Arnaldo Carvalho de Melo
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Alexei Starovoitov,
	Brendan Gregg, Daniel Borkmann, David Ahern, He Kuang, Jiri Olsa,
	Kaixu Xia, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	Zefan Li

This patch introduces a new BPF script to test BPF prologue. The new
script probes at null_lseek, which is the function pointer when we try
to lseek on '/dev/null'.

null_lseek is chosen because it is a function pointer, so we don't need
to consider inlining and LTP.

By extracting file->f_mode, bpf-script-test-prologue.c should know whether
the file is writable or readonly. According to llseek_loop() and
bpf-script-test-prologue.c, one forth of total lseeks should be collected.

This patch improve test__bpf so it can run multiple BPF programs on
different test functions.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: 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: He Kuang <hekuang@huawei.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
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/tests/Build                      |  9 ++-
 tools/perf/tests/bpf-script-test-prologue.c | 35 ++++++++++++
 tools/perf/tests/bpf.c                      | 89 +++++++++++++++++++++++------
 tools/perf/tests/llvm.c                     |  5 ++
 tools/perf/tests/llvm.h                     |  8 +++
 5 files changed, 128 insertions(+), 18 deletions(-)
 create mode 100644 tools/perf/tests/bpf-script-test-prologue.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 2bd5f37..3e98a97 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,7 +32,7 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
-perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
+perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
 perf-y += bpf.o
 perf-y += topology.o
 
@@ -50,6 +50,13 @@ $(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 
+$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c
+	$(call rule_mkdir)
+	$(Q)echo '#include <tests/llvm.h>' > $@
+	$(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 ifdef CONFIG_AUXTRACE
 perf-$(CONFIG_X86) += insn-x86.o
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c
new file mode 100644
index 0000000..7230e62
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-prologue.c
@@ -0,0 +1,35 @@
+/*
+ * bpf-script-test-prologue.c
+ * Test BPF prologue
+ */
+#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 SEC(NAME) __attribute__((section(NAME), used))
+
+#include <uapi/linux/fs.h>
+
+#define FMODE_READ		0x1
+#define FMODE_WRITE		0x2
+
+static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
+	(void *) 6;
+
+SEC("func=null_lseek file->f_mode offset orig")
+int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
+			 unsigned long offset, unsigned long orig)
+{
+	if (err)
+		return 0;
+	if (f_mode & FMODE_WRITE)
+		return 0;
+	if (offset & 1)
+		return 0;
+	if (orig == SEEK_CUR)
+		return 0;
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 4dd701b..5a6290a 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -19,11 +19,35 @@ static int epoll_pwait_loop(void)
 	return 0;
 }
 
-static struct bpf_object *prepare_bpf(void *obj_buf, size_t obj_buf_sz)
+#ifdef HAVE_BPF_PROLOGUE
+
+static int llseek_loop(void)
+{
+	int fds[2], i;
+
+	fds[0] = open("/dev/null", O_RDONLY);
+	fds[1] = open("/dev/null", O_RDWR);
+
+	if (fds[0] < 0 || fds[1] < 0)
+		return -1;
+
+	for (i = 0; i < NR_ITERS; i++) {
+		lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+		lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+	}
+	close(fds[0]);
+	close(fds[1]);
+	return 0;
+}
+
+#endif
+
+static struct bpf_object *prepare_bpf(const char *name, void *obj_buf,
+				      size_t obj_buf_sz)
 {
 	struct bpf_object *obj;
 
-	obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, "[buffer]");
+	obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
 	if (IS_ERR(obj)) {
 		fprintf(stderr, " (compile failed)");
 		return NULL;
@@ -31,7 +55,7 @@ static struct bpf_object *prepare_bpf(void *obj_buf, size_t obj_buf_sz)
 	return obj;
 }
 
-static int do_test(struct bpf_object *obj)
+static int do_test(struct bpf_object *obj, int (*func)(void), int expect)
 {
 	struct record_opts opts = {
 		.target = {
@@ -101,7 +125,7 @@ static int do_test(struct bpf_object *obj)
 	}
 
 	perf_evlist__enable(evlist);
-	epoll_pwait_loop();
+	(*func)();
 	perf_evlist__disable(evlist);
 
 	for (i = 0; i < evlist->nr_mmaps; i++) {
@@ -115,8 +139,8 @@ static int do_test(struct bpf_object *obj)
 		}
 	}
 
-	if (count != (NR_ITERS + 1) / 2) {
-		fprintf(stderr, " (filter result incorrect)");
+	if (count != expect) {
+		fprintf(stderr, " (filter result incorrect: %d != %d)", count, expect);
 		err = -EBADF;
 	}
 
@@ -128,33 +152,32 @@ out:
 	return 0;
 }
 
-int test__bpf(void)
+static int __test__bpf(int index, const char *name,
+		       const char *message_compile,
+		       const char *message_load,
+		       int (*func)(void), int expect)
 {
 	int err;
 	void *obj_buf;
 	size_t obj_buf_sz;
 	struct bpf_object *obj;
 
-	if (geteuid() != 0) {
-		fprintf(stderr, " (try run as root)");
-		return TEST_SKIP;
-	}
-
-	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, LLVM_TESTCASE_BASE);
-
+	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, index);
 	if (!obj_buf || !obj_buf_sz) {
 		if (verbose == 0)
-			fprintf(stderr, " (fix 'perf test LLVM' first)");
+			fprintf(stderr, " (%s)", message_compile);
 		return TEST_SKIP;
 	}
 
-	obj = prepare_bpf(obj_buf, obj_buf_sz);
+	obj = prepare_bpf(name, obj_buf, obj_buf_sz);
 	if (!obj) {
 		err = -EINVAL;
+		if ((verbose == 0) && (message_load[0] != '\0'))
+			fprintf(stderr, " (%s)", message_load);
 		goto out;
 	}
 
-	err = do_test(obj);
+	err = do_test(obj, func, expect);
 	if (err)
 		goto out;
 out:
@@ -164,6 +187,38 @@ out:
 	return 0;
 }
 
+int test__bpf(void)
+{
+	int err;
+
+	if (geteuid() != 0) {
+		fprintf(stderr, " (try run as root)");
+		return TEST_SKIP;
+	}
+
+	err = __test__bpf(LLVM_TESTCASE_BASE,
+			  "[basic_bpf_test]",
+			  "fix 'perf test LLVM' first",
+			  "load bpf object failed",
+			  &epoll_pwait_loop,
+			  (NR_ITERS + 1) / 2);
+	if (err)
+		return err;
+
+#ifdef HAVE_BPF_PROLOGUE
+	err = __test__bpf(LLVM_TESTCASE_BPF_PROLOGUE,
+			  "[bpf_prologue_test]",
+			  "fix kbuild first",
+			  "check your vmlinux setting?",
+			  &llseek_loop,
+			  (NR_ITERS + 1) / 4);
+	return err;
+#else
+	fprintf(stderr, " (skip BPF prologue test)");
+	return TEST_OK;
+#endif
+}
+
 #else
 int test__bpf(void)
 {
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 75cd99f..e722e8a 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -22,6 +22,11 @@ struct llvm_testcase {
 	[LLVM_TESTCASE_KBUILD]	= {.source = test_llvm__bpf_test_kbuild_prog,
 				   .errmsg = "llvm.kbuild-dir can be fixed",
 				   .tried = false},
+	/* Don't output if this one fail. */
+	[LLVM_TESTCASE_BPF_PROLOGUE]	= {
+				   .source = test_llvm__bpf_test_prologue_prog,
+				   .errmsg = "failed for unknown reason",
+				   .tried = false},
 	{.source = NULL}
 };
 
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 78ec01d..c00c1be 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -10,10 +10,18 @@ struct test_llvm__bpf_result {
 
 extern const char test_llvm__bpf_prog[];
 extern const char test_llvm__bpf_test_kbuild_prog[];
+extern const char test_llvm__bpf_test_prologue_prog[];
 
 enum test_llvm__testcase {
 	LLVM_TESTCASE_BASE,
 	LLVM_TESTCASE_KBUILD,
+	/*
+	 * We must put LLVM_TESTCASE_BPF_PROLOGUE after
+	 * LLVM_TESTCASE_KBUILD, so if kbuild test failed,
+	 * don't need to try this one, because it depend on
+	 * kernel header.
+	 */
+	LLVM_TESTCASE_BPF_PROLOGUE,
 	NR_LLVM_TESTCASES,
 };
 void test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, int index);
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 22/22] perf probe: Fix module probing with shortname
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (20 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 21/22] perf test: Test BPF prologue Wang Nan
@ 2015-09-23 11:22 ` Wang Nan
  2015-09-23 13:46 ` [GIT PULL 00/22] perf tools: filtering events using eBPF programs Arnaldo Carvalho de Melo
  22 siblings, 0 replies; 24+ messages in thread
From: Wang Nan @ 2015-09-23 11:22 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, pi3orama, Wang Nan, Namhyung Kim, Jiri Olsa,
	Masami Hiramatsu

After commit 3d39ac538629e4f00a6e1c38d46346f1b8e69505 ("perf machine:
No need to have two DSOs lists"), perf probe with module short name doesn't
work again. For example:

 # lsmod | grep e1000e
 e1000e                233472  0

 # cat /proc/modules | grep e1000e
 e1000e 233472 0 - Live 0xffffffffa0073000

 # cat /proc/kallsyms | grep '\<e1000e_up\>'
 ffffffffa0093860 t e1000e_up[e1000e]

 # perf probe -v -m e1000e --add e1000e_up
 probe-definition(0): e1000e_up
 symbol:e1000e_up file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Failed to find module e1000e.
 Could not open debuginfo. Try to use symbols.
 Looking at the vmlinux_path (7 entries long)
 Using /lib/modules/4.2.0-rc7+/build/vmlinux for symbols
 e1000e_up is out of .text, skip it.
   Error: Failed to add events. Reason: No such file or directory (Code: -2)

This is caused by a misunderstood of dso->kernel in kernel_get_module_dso()
that, for kernel module, dso->kernel is DSO_TYPE_USER. dso->kernel is DSO_TYPE_KERNEL
iff dso is vmlinux.

This patch fix 'perf probe -m' with an ad-hoc way.

After this patch:

 # perf probe -v -m e1000e --add e1000e_up
 probe-definition(0): e1000e_up
 symbol:e1000e_up file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Open Debuginfo file: /lib/modules/4.2.0-rc7+/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
 Try to find probe point from debuginfo.
 Matched function: e1000e_up
 Probe point found: e1000e_up+0
 Found 1 probe_trace_events.
 Opening /sys/kernel/debug/tracing//kprobe_events write=1
 Writing event: p:probe/e1000e_up e1000e:e1000e_up+0
 Added new event:
   probe:e1000e_up      (on e1000e_up in e1000e)

 You can now use it in all perf tools, such as:

 	perf record -e probe:e1000e_up -aR sleep 1

 # perf probe -l
 Failed to find debug information for address ffffffffa0093860
   probe:e1000e_up      (on e1000e_up in e1000e)

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org
---
 tools/perf/util/probe-event.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 2b78e8f..c7d6d3d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -270,7 +270,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
 
 	if (module) {
 		list_for_each_entry(dso, &host_machine->dsos.head, node) {
-			if (!dso->kernel)
+			if (dso->kernel)
 				continue;
 			if (strncmp(dso->short_name + 1, module,
 				    dso->short_name_len - 2) == 0)
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [GIT PULL 00/22] perf tools: filtering events using eBPF programs
  2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
                   ` (21 preceding siblings ...)
  2015-09-23 11:22 ` [PATCH 22/22] perf probe: Fix module probing with shortname Wang Nan
@ 2015-09-23 13:46 ` Arnaldo Carvalho de Melo
  22 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-09-23 13:46 UTC (permalink / raw)
  To: Wang Nan; +Cc: linux-kernel, pi3orama, acme

Em Wed, Sep 23, 2015 at 11:22:21AM +0000, Wang Nan escreveu:
> Hi Arnaldo,
> 
>    I hope you would be satisified with this weeks pull request. In this
> patchset, we totally get rid of dummy events by utilizing Namhyung's newest
> perf probing API.
> 
> Patch 1-6 are different from previous patchset. Plase have a look.
> 
> Due to some reason I can't access my kernel.org account in my company today,
> so I reuse my github repository. I'll update my kernel.org tree at home.
> 
> I'll have a long vacation from Sept. 24. I hope I can discuss with you with
> my private email. However, It seems impossible to modify code and test until
> Oct. 7. If you find some small problem, could you please help me fix them?

Sure thing, I'll continue working on this, we'll get there :-)
 
> Thank you.
> 
> The following changes since commit 5933944f697c15d6f1fb16dc22c02aac9d2ec206:
> 
>   perf tools: Make perf depend on libbpf (2015-09-22 10:17:01 -0300)
> 
> are available in the git repository at:
> 
>   https://github.com/WangNan0/linux.git tags/perf-ebpf-for-acme-20150923
> 
> for you to fetch changes up to 1465cf7b201b8b21c61fa54ffe15094f66e73ab0:
> 
>   perf probe: Fix module probing with shortname (2015-09-23 10:44:58 +0000)
> 
> ----------------------------------------------------------------
> Get rid of dummy events by utilizing new perf probe API.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> 
> ----------------------------------------------------------------
> He Kuang (2):
>       perf tools: Add prologue for BPF programs for fetching arguments
>       perf record: Support custom vmlinux path
> 
> Wang Nan (20):
>       perf ebpf: Add the libbpf glue
>       perf tools: Enable passing bpf object file to --event
>       perf record, bpf: Create probe points for BPF programs
>       perf record: Load eBPF object into kernel
>       perf tools: Collect perf_evsel in BPF object files
>       perf tools: Attach eBPF program to perf event
>       perf record: Add clang options for compiling BPF scripts
>       perf tools: Compile scriptlets to BPF objects when passing '.c' to --event
>       perf test: Enforce LLVM test for BPF test
>       perf test: Add 'perf test BPF'
>       perf probe: Reset args and nargs for probe_trace_event when failure
>       bpf tools: Load a program with different instances using preprocessor
>       perf tools: Add BPF_PROLOGUE config options for further patches
>       perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on
>       perf tools: Generate prologue for BPF programs
>       perf tools: Use same BPF program if arguments are identical
>       perf tools: Allow BPF program attach to uprobe events
>       perf test: Enforce LLVM test, add kbuild test
>       perf test: Test BPF prologue
>       perf probe: Fix module probing with shortname
> 
>  tools/lib/bpf/libbpf.c                      | 143 +++++-
>  tools/lib/bpf/libbpf.h                      |  22 +
>  tools/perf/arch/x86/util/Build              |   1 +
>  tools/perf/builtin-record.c                 |  11 +
>  tools/perf/config/Makefile                  |  12 +
>  tools/perf/perf.c                           |   2 +
>  tools/perf/tests/Build                      |  24 +-
>  tools/perf/tests/bpf-script-example.c       |  48 ++
>  tools/perf/tests/bpf-script-test-kbuild.c   |  21 +
>  tools/perf/tests/bpf-script-test-prologue.c |  35 ++
>  tools/perf/tests/bpf.c                      | 227 ++++++++++
>  tools/perf/tests/builtin-test.c             |  12 +
>  tools/perf/tests/llvm.c                     | 210 ++++++++-
>  tools/perf/tests/llvm.h                     |  29 ++
>  tools/perf/tests/tests.h                    |   3 +
>  tools/perf/util/Build                       |   2 +
>  tools/perf/util/bpf-loader.c                | 676 ++++++++++++++++++++++++++++
>  tools/perf/util/bpf-loader.h                |  95 ++++
>  tools/perf/util/bpf-prologue.c              | 443 ++++++++++++++++++
>  tools/perf/util/bpf-prologue.h              |  34 ++
>  tools/perf/util/evsel.c                     |  17 +
>  tools/perf/util/evsel.h                     |   1 +
>  tools/perf/util/parse-events.c              | 115 +++++
>  tools/perf/util/parse-events.h              |   9 +
>  tools/perf/util/parse-events.l              |   6 +
>  tools/perf/util/parse-events.y              |  29 +-
>  tools/perf/util/probe-event.c               |   2 +-
>  tools/perf/util/probe-finder.c              |   4 +
>  28 files changed, 2202 insertions(+), 31 deletions(-)
>  create mode 100644 tools/perf/tests/bpf-script-example.c
>  create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c
>  create mode 100644 tools/perf/tests/bpf-script-test-prologue.c
>  create mode 100644 tools/perf/tests/bpf.c
>  create mode 100644 tools/perf/tests/llvm.h
>  create mode 100644 tools/perf/util/bpf-loader.c
>  create mode 100644 tools/perf/util/bpf-loader.h
>  create mode 100644 tools/perf/util/bpf-prologue.c
>  create mode 100644 tools/perf/util/bpf-prologue.h
> -- 
> 1.8.3.4

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2015-09-23 13:46 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-23 11:22 [GIT PULL 00/22] perf tools: filtering events using eBPF programs Wang Nan
2015-09-23 11:22 ` [PATCH 01/22] perf ebpf: Add the libbpf glue Wang Nan
2015-09-23 11:22 ` [PATCH 02/22] perf tools: Enable passing bpf object file to --event Wang Nan
2015-09-23 11:22 ` [PATCH 03/22] perf record, bpf: Create probe points for BPF programs Wang Nan
2015-09-23 11:22 ` [PATCH 04/22] perf record: Load eBPF object into kernel Wang Nan
2015-09-23 11:22 ` [PATCH 05/22] perf tools: Collect perf_evsel in BPF object files Wang Nan
2015-09-23 11:22 ` [PATCH 06/22] perf tools: Attach eBPF program to perf event Wang Nan
2015-09-23 11:22 ` [PATCH 07/22] perf record: Add clang options for compiling BPF scripts Wang Nan
2015-09-23 11:22 ` [PATCH 08/22] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event Wang Nan
2015-09-23 11:22 ` [PATCH 09/22] perf test: Enforce LLVM test for BPF test Wang Nan
2015-09-23 11:22 ` [PATCH 10/22] perf test: Add 'perf test BPF' Wang Nan
2015-09-23 11:22 ` [PATCH 11/22] perf probe: Reset args and nargs for probe_trace_event when failure Wang Nan
2015-09-23 11:22 ` [PATCH 12/22] bpf tools: Load a program with different instances using preprocessor Wang Nan
2015-09-23 11:22 ` [PATCH 13/22] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan
2015-09-23 11:22 ` [PATCH 14/22] perf tools: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on Wang Nan
2015-09-23 11:22 ` [PATCH 15/22] perf tools: Add prologue for BPF programs for fetching arguments Wang Nan
2015-09-23 11:22 ` [PATCH 16/22] perf tools: Generate prologue for BPF programs Wang Nan
2015-09-23 11:22 ` [PATCH 17/22] perf tools: Use same BPF program if arguments are identical Wang Nan
2015-09-23 11:22 ` [PATCH 18/22] perf record: Support custom vmlinux path Wang Nan
2015-09-23 11:22 ` [PATCH 19/22] perf tools: Allow BPF program attach to uprobe events Wang Nan
2015-09-23 11:22 ` [PATCH 20/22] perf test: Enforce LLVM test, add kbuild test Wang Nan
2015-09-23 11:22 ` [PATCH 21/22] perf test: Test BPF prologue Wang Nan
2015-09-23 11:22 ` [PATCH 22/22] perf probe: Fix module probing with shortname Wang Nan
2015-09-23 13:46 ` [GIT PULL 00/22] perf tools: filtering events using eBPF programs Arnaldo Carvalho de Melo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).