linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GIT PULL 00/11] perf/core improvements and fixes
@ 2015-11-06 20:54 Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 01/11] perf stat: Make stat options global Arnaldo Carvalho de Melo
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Arnaldo Carvalho de Melo, Adrian Hunter,
	Alexei Starovoitov, Andi Kleen, David Ahern, He Kuang, Jiri Olsa,
	Kan Liang, Masami Hiramatsu, Namhyung Kim, Peter Zijlstra,
	pi3orama, Wang Nan, Zefan Li, Arnaldo Carvalho de Melo

Hi Ingo,

	Please consider pulling, this is on top of the perf-core-for-mingo tag,
that is outstanding.

Best regards,

- Arnaldo

The following changes since commit 0014de172d228e450377d1fd079d94e67128d27f:

  perf sched latency: Fix thread pid reuse issue (2015-11-05 12:51:00 -0300)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo-2

for you to fetch changes up to 345c99a303e1d97b407bf99190314a878d59ca92:

  perf test: Do not be case sensitive when searching for matching tests (2015-11-06 17:50:04 -0300)

----------------------------------------------------------------
perf/core improvements and fixes:

- libbpf error reporting improvements, using a strerror interface to
  more precisely tell the user about problems with the provided
  scriptlet, be it in C or as a ready made object file (Wang Nan)

- Do not be case sensitive when searching for matching 'perf test'
  entries (Arnaldo Carvalho de Melo)

- Inform the user about objdump failures in 'perf annotate' (Andi Kleen)

Infrastructure:

- Improve the LLVM 'perf test' entry, introduce new ones for
  BPF and kbuild to check the environment used by clang to
  compile .c scriptlets (Wang Nan)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

----------------------------------------------------------------
Andi Kleen (1):
      perf annotate: Inform the user about objdump failures in --stdio

Arnaldo Carvalho de Melo (1):
      perf test: Do not be case sensitive when searching for matching tests

Jiri Olsa (1):
      perf stat: Make stat options global

Masami Hiramatsu (1):
      perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy

Wang Nan (7):
      bpf tools: Improve libbpf error reporting
      bpf tools: Add new API bpf_object__get_kversion()
      perf tools: Make fetch_kernel_version() publicly available
      perf bpf: Improve BPF related error messages
      perf test: Enhance the LLVM test: update basic BPF test program
      perf test: Enhance the LLVM tests: add kbuild test
      perf test: Add 'perf test BPF'

 tools/lib/bpf/libbpf.c                    | 167 +++++++++++++++++-------
 tools/lib/bpf/libbpf.h                    |  21 +++
 tools/perf/builtin-stat.c                 | 163 +++++++++++------------
 tools/perf/tests/Build                    |  17 ++-
 tools/perf/tests/bpf-script-example.c     |   4 +
 tools/perf/tests/bpf-script-test-kbuild.c |  21 +++
 tools/perf/tests/bpf.c                    | 209 ++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c           |   6 +-
 tools/perf/tests/llvm.c                   | 137 +++++++++++++++-----
 tools/perf/tests/llvm.h                   |  18 +++
 tools/perf/tests/tests.h                  |   1 +
 tools/perf/util/annotate.c                |  20 ++-
 tools/perf/util/bpf-loader.c              | 139 +++++++++++++++++---
 tools/perf/util/bpf-loader.h              |  33 +++++
 tools/perf/util/llvm-utils.c              |  49 +++----
 tools/perf/util/parse-events.c            |  11 +-
 tools/perf/util/probe-event.c             |   7 +-
 tools/perf/util/util.c                    |  30 +++++
 tools/perf/util/util.h                    |   8 ++
 19 files changed, 836 insertions(+), 225 deletions(-)
 create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c
 create mode 100644 tools/perf/tests/bpf.c
 create mode 100644 tools/perf/tests/llvm.h

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

* [PATCH 01/11] perf stat: Make stat options global
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 02/11] perf annotate: Inform the user about objdump failures in --stdio Arnaldo Carvalho de Melo
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Jiri Olsa, David Ahern, Namhyung Kim,
	Peter Zijlstra, Arnaldo Carvalho de Melo

From: Jiri Olsa <jolsa@kernel.org>

So they can be used in perf stat record command in following patch.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Kan Liang <kan.liang@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1446734469-11352-2-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-stat.c | 163 +++++++++++++++++++++++-----------------------
 1 file changed, 82 insertions(+), 81 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index b74ee0f2e714..e77880b5094d 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -122,6 +122,9 @@ static bool			forever				= false;
 static struct timespec		ref_time;
 static struct cpu_map		*aggr_map;
 static aggr_get_id_t		aggr_get_id;
+static bool			append_file;
+static const char		*output_name;
+static int			output_fd;
 
 static volatile int done = 0;
 
@@ -927,6 +930,67 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
 	return 0;
 }
 
+static const struct option stat_options[] = {
+	OPT_BOOLEAN('T', "transaction", &transaction_run,
+		    "hardware transaction statistics"),
+	OPT_CALLBACK('e', "event", &evsel_list, "event",
+		     "event selector. use 'perf list' to list available events",
+		     parse_events_option),
+	OPT_CALLBACK(0, "filter", &evsel_list, "filter",
+		     "event filter", parse_filter),
+	OPT_BOOLEAN('i', "no-inherit", &no_inherit,
+		    "child tasks do not inherit counters"),
+	OPT_STRING('p', "pid", &target.pid, "pid",
+		   "stat events on existing process id"),
+	OPT_STRING('t', "tid", &target.tid, "tid",
+		   "stat events on existing thread id"),
+	OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
+		    "system-wide collection from all CPUs"),
+	OPT_BOOLEAN('g', "group", &group,
+		    "put the counters into a counter group"),
+	OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
+	OPT_INCR('v', "verbose", &verbose,
+		    "be more verbose (show counter open errors, etc)"),
+	OPT_INTEGER('r', "repeat", &run_count,
+		    "repeat command and print average + stddev (max: 100, forever: 0)"),
+	OPT_BOOLEAN('n', "null", &null_run,
+		    "null run - dont start any counters"),
+	OPT_INCR('d', "detailed", &detailed_run,
+		    "detailed run - start a lot of events"),
+	OPT_BOOLEAN('S', "sync", &sync_run,
+		    "call sync() before starting a run"),
+	OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
+			   "print large numbers with thousands\' separators",
+			   stat__set_big_num),
+	OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
+		    "list of cpus to monitor in system-wide"),
+	OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
+		    "disable CPU count aggregation", AGGR_NONE),
+	OPT_STRING('x', "field-separator", &csv_sep, "separator",
+		   "print counts with custom separator"),
+	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+		     "monitor event in cgroup name only", parse_cgroups),
+	OPT_STRING('o', "output", &output_name, "file", "output file name"),
+	OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
+	OPT_INTEGER(0, "log-fd", &output_fd,
+		    "log output to fd, instead of stderr"),
+	OPT_STRING(0, "pre", &pre_cmd, "command",
+			"command to run prior to the measured command"),
+	OPT_STRING(0, "post", &post_cmd, "command",
+			"command to run after to the measured command"),
+	OPT_UINTEGER('I', "interval-print", &stat_config.interval,
+		    "print counts at regular interval in ms (>= 10)"),
+	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
+		     "aggregate counts per processor socket", AGGR_SOCKET),
+	OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
+		     "aggregate counts per physical processor core", AGGR_CORE),
+	OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
+		     "aggregate counts per thread", AGGR_THREAD),
+	OPT_UINTEGER('D', "delay", &initial_delay,
+		     "ms to wait before starting measurement after program start"),
+	OPT_END()
+};
+
 static int perf_stat__get_socket(struct cpu_map *map, int cpu)
 {
 	return cpu_map__get_socket(map, cpu, NULL);
@@ -1174,69 +1238,6 @@ static int add_default_attributes(void)
 
 int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-	bool append_file = false;
-	int output_fd = 0;
-	const char *output_name	= NULL;
-	const struct option options[] = {
-	OPT_BOOLEAN('T', "transaction", &transaction_run,
-		    "hardware transaction statistics"),
-	OPT_CALLBACK('e', "event", &evsel_list, "event",
-		     "event selector. use 'perf list' to list available events",
-		     parse_events_option),
-	OPT_CALLBACK(0, "filter", &evsel_list, "filter",
-		     "event filter", parse_filter),
-	OPT_BOOLEAN('i', "no-inherit", &no_inherit,
-		    "child tasks do not inherit counters"),
-	OPT_STRING('p', "pid", &target.pid, "pid",
-		   "stat events on existing process id"),
-	OPT_STRING('t', "tid", &target.tid, "tid",
-		   "stat events on existing thread id"),
-	OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
-		    "system-wide collection from all CPUs"),
-	OPT_BOOLEAN('g', "group", &group,
-		    "put the counters into a counter group"),
-	OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
-	OPT_INCR('v', "verbose", &verbose,
-		    "be more verbose (show counter open errors, etc)"),
-	OPT_INTEGER('r', "repeat", &run_count,
-		    "repeat command and print average + stddev (max: 100, forever: 0)"),
-	OPT_BOOLEAN('n', "null", &null_run,
-		    "null run - dont start any counters"),
-	OPT_INCR('d', "detailed", &detailed_run,
-		    "detailed run - start a lot of events"),
-	OPT_BOOLEAN('S', "sync", &sync_run,
-		    "call sync() before starting a run"),
-	OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
-			   "print large numbers with thousands\' separators",
-			   stat__set_big_num),
-	OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
-		    "list of cpus to monitor in system-wide"),
-	OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
-		    "disable CPU count aggregation", AGGR_NONE),
-	OPT_STRING('x', "field-separator", &csv_sep, "separator",
-		   "print counts with custom separator"),
-	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
-		     "monitor event in cgroup name only", parse_cgroups),
-	OPT_STRING('o', "output", &output_name, "file", "output file name"),
-	OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
-	OPT_INTEGER(0, "log-fd", &output_fd,
-		    "log output to fd, instead of stderr"),
-	OPT_STRING(0, "pre", &pre_cmd, "command",
-			"command to run prior to the measured command"),
-	OPT_STRING(0, "post", &post_cmd, "command",
-			"command to run after to the measured command"),
-	OPT_UINTEGER('I', "interval-print", &stat_config.interval,
-		    "print counts at regular interval in ms (>= 10)"),
-	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
-		     "aggregate counts per processor socket", AGGR_SOCKET),
-	OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
-		     "aggregate counts per physical processor core", AGGR_CORE),
-	OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
-		     "aggregate counts per thread", AGGR_THREAD),
-	OPT_UINTEGER('D', "delay", &initial_delay,
-		     "ms to wait before starting measurement after program start"),
-	OPT_END()
-	};
 	const char * const stat_usage[] = {
 		"perf stat [<options>] [<command>]",
 		NULL
@@ -1252,7 +1253,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (evsel_list == NULL)
 		return -ENOMEM;
 
-	argc = parse_options(argc, argv, options, stat_usage,
+	argc = parse_options(argc, argv, stat_options, stat_usage,
 		PARSE_OPT_STOP_AT_NON_OPTION);
 
 	interval = stat_config.interval;
@@ -1262,14 +1263,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	if (output_name && output_fd) {
 		fprintf(stderr, "cannot use both --output and --log-fd\n");
-		parse_options_usage(stat_usage, options, "o", 1);
-		parse_options_usage(NULL, options, "log-fd", 0);
+		parse_options_usage(stat_usage, stat_options, "o", 1);
+		parse_options_usage(NULL, stat_options, "log-fd", 0);
 		goto out;
 	}
 
 	if (output_fd < 0) {
 		fprintf(stderr, "argument to --log-fd must be a > 0\n");
-		parse_options_usage(stat_usage, options, "log-fd", 0);
+		parse_options_usage(stat_usage, stat_options, "log-fd", 0);
 		goto out;
 	}
 
@@ -1309,8 +1310,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 		/* User explicitly passed -B? */
 		if (big_num_opt == 1) {
 			fprintf(stderr, "-B option not supported with -x\n");
-			parse_options_usage(stat_usage, options, "B", 1);
-			parse_options_usage(NULL, options, "x", 1);
+			parse_options_usage(stat_usage, stat_options, "B", 1);
+			parse_options_usage(NULL, stat_options, "x", 1);
 			goto out;
 		} else /* Nope, so disable big number formatting */
 			big_num = false;
@@ -1318,11 +1319,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 		big_num = false;
 
 	if (!argc && target__none(&target))
-		usage_with_options(stat_usage, options);
+		usage_with_options(stat_usage, stat_options);
 
 	if (run_count < 0) {
 		pr_err("Run count must be a positive number\n");
-		parse_options_usage(stat_usage, options, "r", 1);
+		parse_options_usage(stat_usage, stat_options, "r", 1);
 		goto out;
 	} else if (run_count == 0) {
 		forever = true;
@@ -1332,8 +1333,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 	if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
 		fprintf(stderr, "The --per-thread option is only available "
 			"when monitoring via -p -t options.\n");
-		parse_options_usage(NULL, options, "p", 1);
-		parse_options_usage(NULL, options, "t", 1);
+		parse_options_usage(NULL, stat_options, "p", 1);
+		parse_options_usage(NULL, stat_options, "t", 1);
 		goto out;
 	}
 
@@ -1347,9 +1348,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 		fprintf(stderr, "both cgroup and no-aggregation "
 			"modes only available in system-wide mode\n");
 
-		parse_options_usage(stat_usage, options, "G", 1);
-		parse_options_usage(NULL, options, "A", 1);
-		parse_options_usage(NULL, options, "a", 1);
+		parse_options_usage(stat_usage, stat_options, "G", 1);
+		parse_options_usage(NULL, stat_options, "A", 1);
+		parse_options_usage(NULL, stat_options, "a", 1);
 		goto out;
 	}
 
@@ -1361,12 +1362,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (perf_evlist__create_maps(evsel_list, &target) < 0) {
 		if (target__has_task(&target)) {
 			pr_err("Problems finding threads of monitor\n");
-			parse_options_usage(stat_usage, options, "p", 1);
-			parse_options_usage(NULL, options, "t", 1);
+			parse_options_usage(stat_usage, stat_options, "p", 1);
+			parse_options_usage(NULL, stat_options, "t", 1);
 		} else if (target__has_cpu(&target)) {
 			perror("failed to parse CPUs map");
-			parse_options_usage(stat_usage, options, "C", 1);
-			parse_options_usage(NULL, options, "a", 1);
+			parse_options_usage(stat_usage, stat_options, "C", 1);
+			parse_options_usage(NULL, stat_options, "a", 1);
 		}
 		goto out;
 	}
@@ -1381,7 +1382,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (interval && interval < 100) {
 		if (interval < 10) {
 			pr_err("print interval must be >= 10ms\n");
-			parse_options_usage(stat_usage, options, "I", 1);
+			parse_options_usage(stat_usage, stat_options, "I", 1);
 			goto out;
 		} else
 			pr_warning("print interval < 100ms. "
-- 
2.1.0


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

* [PATCH 02/11] perf annotate: Inform the user about objdump failures in --stdio
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 01/11] perf stat: Make stat options global Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 03/11] perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy Arnaldo Carvalho de Melo
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Andi Kleen, Jiri Olsa, Namhyung Kim,
	Arnaldo Carvalho de Melo

From: Andi Kleen <ak@linux.intel.com>

When the browser fails to annotate it is difficult for users to find out
what went wrong.

Add some errors for objdump failures that are displayed in the UI.

Note it would be even better to handle these errors smarter, like
falling back to the binary when the debug info is somehow corrupted. But
for now just giving a better error is an improvement.

Committer note:

This works for --stdio, where errors just scroll by the screen:

  # perf annotate --stdio intel_idle
  Failure running objdump  --start-address=0xffffffff81418290 --stop-address=0xffffffff814183ae -l -d --no-show-raw -S -C /root/.debug/.build-id/28/2777c262e6b3c0451375163c9a81c893218ab1 2>/dev/null|grep -v /root/.debug/.build-id/28/2777c262e6b3c0451375163c9a81c893218ab1|expand
   Percent |      Source code & Disassembly of vmlinux for cycles:pp
  ------------------------------------------------------------------

And with that one can use that command line to try to find out more about what
happened instead of getting a blank screen, an improvement.

We need tho to improve this further to get it to work with other UIs, like
--tui and --gtk, where it continues showing a blank screen, no messages, as
the pr_err() used is enough just for --stdio.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1446779167-18949-1-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/annotate.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 0fc8d7a2fea5..f2974da0185a 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1084,6 +1084,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
 	struct kcore_extract kce;
 	bool delete_extract = false;
 	int lineno = 0;
+	int nline;
 
 	if (filename)
 		symbol__join_symfs(symfs_filename, filename);
@@ -1179,6 +1180,9 @@ fallback:
 
 		ret = decompress_to_file(m.ext, symfs_filename, fd);
 
+		if (ret)
+			pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
+
 		free(m.ext);
 		close(fd);
 
@@ -1204,13 +1208,25 @@ fallback:
 	pr_debug("Executing: %s\n", command);
 
 	file = popen(command, "r");
-	if (!file)
+	if (!file) {
+		pr_err("Failure running %s\n", command);
+		/*
+		 * If we were using debug info should retry with
+		 * original binary.
+		 */
 		goto out_remove_tmp;
+	}
 
-	while (!feof(file))
+	nline = 0;
+	while (!feof(file)) {
 		if (symbol__parse_objdump_line(sym, map, file, privsize,
 			    &lineno) < 0)
 			break;
+		nline++;
+	}
+
+	if (nline == 0)
+		pr_err("No output from %s\n", command);
 
 	/*
 	 * kallsyms does not have symbol sizes so there may a nop at the end.
-- 
2.1.0


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

* [PATCH 03/11] perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 01/11] perf stat: Make stat options global Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 02/11] perf annotate: Inform the user about objdump failures in --stdio Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 04/11] bpf tools: Improve libbpf error reporting Arnaldo Carvalho de Melo
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Masami Hiramatsu, Jiri Olsa, Namhyung Kim,
	Wang Nan, Zefan Li, Arnaldo Carvalho de Melo

From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

In find_perf_probe_point_from_map(), the 'ret' variable is initialized
with -ENOENT but overwritten by the return code of
kernel_get_symbol_address_by_name(), and after that it is re-initialized
with -ENOENT again.

Setting ret=-ENOENT twice looks a bit redundant. This avoids the
overwriting and just returns -ENOENT if some error happens to simplify
the code.

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

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e659c4faddec..03875f9154e7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
 		sym = map__find_symbol(map, addr, NULL);
 	} else {
 		if (tp->symbol && !addr) {
-			ret = kernel_get_symbol_address_by_name(tp->symbol,
-							&addr, true, false);
-			if (ret < 0)
+			if (kernel_get_symbol_address_by_name(tp->symbol,
+						&addr, true, false) < 0)
 				goto out;
 		}
 		if (addr) {
@@ -1906,8 +1905,6 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
 		}
 	}
 
-	/* ret may has be overwritten so reset it */
-	ret = -ENOENT;
 	if (!sym)
 		goto out;
 
-- 
2.1.0


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

* [PATCH 04/11] bpf tools: Improve libbpf error reporting
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (2 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 03/11] perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 05/11] bpf tools: Add new API bpf_object__get_kversion() Arnaldo Carvalho de Melo
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

In this patch, a series of libbpf specific error numbers and
libbpf_strerror() are introduced to help reporting errors.

Functions are updated to pass correct the error number through the
CHECK_ERR() macro.

All users of bpf_object__open{_buffer}() and bpf_program__title() in
perf are modified accordingly. In addition, due to the error codes
changing, bpf__strerror_load() is also modified to use them.

bpf__strerror_head() is also changed accordingly so it can parse libbpf
errors. bpf_loader_strerror() is introduced for that purpose, and will
be improved by the following patch.

load_program() is improved not to dump log buffer if it is empty. log
buffer is also used to deduce whether the error was caused by an invalid
program or other problem.

v1 -> v2:

 - Using macro for error code.

 - Fetch error message based on array index, eliminate for-loop.

 - Use log buffer to detect the reason of failure. 3 new error code
   are introduced to replace LIBBPF_ERRNO__LOAD.

In v1:

  # perf record -e ./test_ill_program.o ls
  event syntax error: './test_ill_program.o'
                       \___ Failed to load program: Validate your program and check 'license'/'version' sections in your object
  SKIP

  # perf record -e ./test_kversion_nomatch_program.o ls
  event syntax error: './test_kversion_nomatch_program.o'
                       \___ Failed to load program: Validate your program and check 'license'/'version' sections in your object
  SKIP

  # perf record -e ./test_big_program.o ls
  event syntax error: './test_big_program.o'
                       \___ Failed to load program: Validate your program and check 'license'/'version' sections in your object
  SKIP

  In v2:

  # perf record -e ./test_ill_program.o ls
  event syntax error: './test_ill_program.o'
                       \___ Kernel verifier blocks program loading
  SKIP

  # perf record -e ./test_kversion_nomatch_program.o
  event syntax error: './test_kversion_nomatch_program.o'
                       \___ Incorrect kernel version
  SKIP
  (Will be further improved by following patches)

  # perf record -e ./test_big_program.o
  event syntax error: './test_big_program.o'
                       \___ Program too big
  SKIP

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446817783-86722-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c         | 159 ++++++++++++++++++++++++++++-------------
 tools/lib/bpf/libbpf.h         |  20 ++++++
 tools/perf/tests/llvm.c        |   2 +-
 tools/perf/util/bpf-loader.c   |  33 +++++++--
 tools/perf/util/parse-events.c |   4 +-
 5 files changed, 159 insertions(+), 59 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 9f3c8cf9249b..07b492d3dfaa 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -61,6 +61,60 @@ void libbpf_set_print(libbpf_print_fn_t warn,
 	__pr_debug = debug;
 }
 
+#define STRERR_BUFSIZE  128
+
+#define ERRNO_OFFSET(e)		((e) - __LIBBPF_ERRNO__START)
+#define ERRCODE_OFFSET(c)	ERRNO_OFFSET(LIBBPF_ERRNO__##c)
+#define NR_ERRNO	(__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
+
+static const char *libbpf_strerror_table[NR_ERRNO] = {
+	[ERRCODE_OFFSET(LIBELF)]	= "Something wrong in libelf",
+	[ERRCODE_OFFSET(FORMAT)]	= "BPF object format invalid",
+	[ERRCODE_OFFSET(KVERSION)]	= "'version' section incorrect or lost",
+	[ERRCODE_OFFSET(ENDIAN)]	= "Endian missmatch",
+	[ERRCODE_OFFSET(INTERNAL)]	= "Internal error in libbpf",
+	[ERRCODE_OFFSET(RELOC)]		= "Relocation failed",
+	[ERRCODE_OFFSET(VERIFY)]	= "Kernel verifier blocks program loading",
+	[ERRCODE_OFFSET(PROG2BIG)]	= "Program too big",
+	[ERRCODE_OFFSET(KVER)]		= "Incorrect kernel version",
+};
+
+int libbpf_strerror(int err, char *buf, size_t size)
+{
+	if (!buf || !size)
+		return -1;
+
+	err = err > 0 ? err : -err;
+
+	if (err < __LIBBPF_ERRNO__START) {
+		int ret;
+
+		ret = strerror_r(err, buf, size);
+		buf[size - 1] = '\0';
+		return ret;
+	}
+
+	if (err < __LIBBPF_ERRNO__END) {
+		const char *msg;
+
+		msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
+		snprintf(buf, size, "%s", msg);
+		buf[size - 1] = '\0';
+		return 0;
+	}
+
+	snprintf(buf, size, "Unknown libbpf error %d", err);
+	buf[size - 1] = '\0';
+	return -1;
+}
+
+#define CHECK_ERR(action, err, out) do {	\
+	err = action;			\
+	if (err)			\
+		goto out;		\
+} while(0)
+
+
 /* Copied from tools/perf/util/util.h */
 #ifndef zfree
 # define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
@@ -258,7 +312,7 @@ static struct bpf_object *bpf_object__new(const char *path,
 	obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
 	if (!obj) {
 		pr_warning("alloc memory failed for %s\n", path);
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	strcpy(obj->path, path);
@@ -305,7 +359,7 @@ static int bpf_object__elf_init(struct bpf_object *obj)
 
 	if (obj_elf_valid(obj)) {
 		pr_warning("elf init: internal error\n");
-		return -EEXIST;
+		return -LIBBPF_ERRNO__LIBELF;
 	}
 
 	if (obj->efile.obj_buf_sz > 0) {
@@ -331,14 +385,14 @@ static int bpf_object__elf_init(struct bpf_object *obj)
 	if (!obj->efile.elf) {
 		pr_warning("failed to open %s as ELF file\n",
 				obj->path);
-		err = -EINVAL;
+		err = -LIBBPF_ERRNO__LIBELF;
 		goto errout;
 	}
 
 	if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
 		pr_warning("failed to get EHDR from %s\n",
 				obj->path);
-		err = -EINVAL;
+		err = -LIBBPF_ERRNO__FORMAT;
 		goto errout;
 	}
 	ep = &obj->efile.ehdr;
@@ -346,7 +400,7 @@ static int bpf_object__elf_init(struct bpf_object *obj)
 	if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
 		pr_warning("%s is not an eBPF object file\n",
 			obj->path);
-		err = -EINVAL;
+		err = -LIBBPF_ERRNO__FORMAT;
 		goto errout;
 	}
 
@@ -374,14 +428,14 @@ bpf_object__check_endianness(struct bpf_object *obj)
 			goto mismatch;
 		break;
 	default:
-		return -EINVAL;
+		return -LIBBPF_ERRNO__ENDIAN;
 	}
 
 	return 0;
 
 mismatch:
 	pr_warning("Error: endianness mismatch.\n");
-	return -EINVAL;
+	return -LIBBPF_ERRNO__ENDIAN;
 }
 
 static int
@@ -402,7 +456,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
 
 	if (size != sizeof(kver)) {
 		pr_warning("invalid kver section in %s\n", obj->path);
-		return -EINVAL;
+		return -LIBBPF_ERRNO__FORMAT;
 	}
 	memcpy(&kver, data, sizeof(kver));
 	obj->kern_version = kver;
@@ -444,7 +498,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 	if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
 		pr_warning("failed to get e_shstrndx from %s\n",
 			   obj->path);
-		return -EINVAL;
+		return -LIBBPF_ERRNO__FORMAT;
 	}
 
 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
@@ -456,7 +510,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 		if (gelf_getshdr(scn, &sh) != &sh) {
 			pr_warning("failed to get section header from %s\n",
 				   obj->path);
-			err = -EINVAL;
+			err = -LIBBPF_ERRNO__FORMAT;
 			goto out;
 		}
 
@@ -464,7 +518,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 		if (!name) {
 			pr_warning("failed to get section name from %s\n",
 				   obj->path);
-			err = -EINVAL;
+			err = -LIBBPF_ERRNO__FORMAT;
 			goto out;
 		}
 
@@ -472,7 +526,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 		if (!data) {
 			pr_warning("failed to get section data from %s(%s)\n",
 				   name, obj->path);
-			err = -EINVAL;
+			err = -LIBBPF_ERRNO__FORMAT;
 			goto out;
 		}
 		pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n",
@@ -495,7 +549,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 			if (obj->efile.symbols) {
 				pr_warning("bpf: multiple SYMTAB in %s\n",
 					   obj->path);
-				err = -EEXIST;
+				err = -LIBBPF_ERRNO__FORMAT;
 			} else
 				obj->efile.symbols = data;
 		} else if ((sh.sh_type == SHT_PROGBITS) &&
@@ -504,7 +558,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 			err = bpf_object__add_program(obj, data->d_buf,
 						      data->d_size, name, idx);
 			if (err) {
-				char errmsg[128];
+				char errmsg[STRERR_BUFSIZE];
+
 				strerror_r(-err, errmsg, sizeof(errmsg));
 				pr_warning("failed to alloc program %s (%s): %s",
 					   name, obj->path, errmsg);
@@ -576,7 +631,7 @@ bpf_program__collect_reloc(struct bpf_program *prog,
 
 		if (!gelf_getrel(data, i, &rel)) {
 			pr_warning("relocation: failed to get %d reloc\n", i);
-			return -EINVAL;
+			return -LIBBPF_ERRNO__FORMAT;
 		}
 
 		insn_idx = rel.r_offset / sizeof(struct bpf_insn);
@@ -587,20 +642,20 @@ bpf_program__collect_reloc(struct bpf_program *prog,
 				 &sym)) {
 			pr_warning("relocation: symbol %"PRIx64" not found\n",
 				   GELF_R_SYM(rel.r_info));
-			return -EINVAL;
+			return -LIBBPF_ERRNO__FORMAT;
 		}
 
 		if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
 			pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
 				   insn_idx, insns[insn_idx].code);
-			return -EINVAL;
+			return -LIBBPF_ERRNO__RELOC;
 		}
 
 		map_idx = sym.st_value / sizeof(struct bpf_map_def);
 		if (map_idx >= nr_maps) {
 			pr_warning("bpf relocation: map_idx %d large than %d\n",
 				   (int)map_idx, (int)nr_maps - 1);
-			return -EINVAL;
+			return -LIBBPF_ERRNO__RELOC;
 		}
 
 		prog->reloc_desc[i].insn_idx = insn_idx;
@@ -683,7 +738,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds)
 		if (insn_idx >= (int)prog->insns_cnt) {
 			pr_warning("relocation out of range: '%s'\n",
 				   prog->section_name);
-			return -ERANGE;
+			return -LIBBPF_ERRNO__RELOC;
 		}
 		insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
 		insns[insn_idx].imm = map_fds[map_idx];
@@ -721,7 +776,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
 
 	if (!obj_elf_valid(obj)) {
 		pr_warning("Internal error: elf object is closed\n");
-		return -EINVAL;
+		return -LIBBPF_ERRNO__INTERNAL;
 	}
 
 	for (i = 0; i < obj->efile.nr_reloc; i++) {
@@ -734,21 +789,21 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
 
 		if (shdr->sh_type != SHT_REL) {
 			pr_warning("internal error at %d\n", __LINE__);
-			return -EINVAL;
+			return -LIBBPF_ERRNO__INTERNAL;
 		}
 
 		prog = bpf_object__find_prog_by_idx(obj, idx);
 		if (!prog) {
 			pr_warning("relocation failed: no %d section\n",
 				   idx);
-			return -ENOENT;
+			return -LIBBPF_ERRNO__RELOC;
 		}
 
 		err = bpf_program__collect_reloc(prog, nr_maps,
 						 shdr, data,
 						 obj->efile.symbols);
 		if (err)
-			return -EINVAL;
+			return err;
 	}
 	return 0;
 }
@@ -777,13 +832,23 @@ load_program(struct bpf_insn *insns, int insns_cnt,
 		goto out;
 	}
 
-	ret = -EINVAL;
+	ret = -LIBBPF_ERRNO__LOAD;
 	pr_warning("load bpf program failed: %s\n", strerror(errno));
 
-	if (log_buf) {
+	if (log_buf && log_buf[0] != '\0') {
+		ret = -LIBBPF_ERRNO__VERIFY;
 		pr_warning("-- BEGIN DUMP LOG ---\n");
 		pr_warning("\n%s\n", log_buf);
 		pr_warning("-- END LOG --\n");
+	} else {
+		if (insns_cnt >= BPF_MAXINSNS) {
+			pr_warning("Program too large (%d insns), at most %d insns\n",
+				   insns_cnt, BPF_MAXINSNS);
+			ret = -LIBBPF_ERRNO__PROG2BIG;
+		} else if (log_buf) {
+			pr_warning("log buffer is empty\n");
+			ret = -LIBBPF_ERRNO__KVER;
+		}
 	}
 
 out:
@@ -831,7 +896,7 @@ static int bpf_object__validate(struct bpf_object *obj)
 	if (obj->kern_version == 0) {
 		pr_warning("%s doesn't provide kernel version\n",
 			   obj->path);
-		return -EINVAL;
+		return -LIBBPF_ERRNO__KVERSION;
 	}
 	return 0;
 }
@@ -840,32 +905,28 @@ static struct bpf_object *
 __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
 {
 	struct bpf_object *obj;
+	int err;
 
 	if (elf_version(EV_CURRENT) == EV_NONE) {
 		pr_warning("failed to init libelf for %s\n", path);
-		return NULL;
+		return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
 	}
 
 	obj = bpf_object__new(path, obj_buf, obj_buf_sz);
-	if (!obj)
-		return NULL;
+	if (IS_ERR(obj))
+		return obj;
 
-	if (bpf_object__elf_init(obj))
-		goto out;
-	if (bpf_object__check_endianness(obj))
-		goto out;
-	if (bpf_object__elf_collect(obj))
-		goto out;
-	if (bpf_object__collect_reloc(obj))
-		goto out;
-	if (bpf_object__validate(obj))
-		goto out;
+	CHECK_ERR(bpf_object__elf_init(obj), err, out);
+	CHECK_ERR(bpf_object__check_endianness(obj), err, out);
+	CHECK_ERR(bpf_object__elf_collect(obj), err, out);
+	CHECK_ERR(bpf_object__collect_reloc(obj), err, out);
+	CHECK_ERR(bpf_object__validate(obj), err, out);
 
 	bpf_object__elf_finish(obj);
 	return obj;
 out:
 	bpf_object__close(obj);
-	return NULL;
+	return ERR_PTR(err);
 }
 
 struct bpf_object *bpf_object__open(const char *path)
@@ -922,6 +983,8 @@ int bpf_object__unload(struct bpf_object *obj)
 
 int bpf_object__load(struct bpf_object *obj)
 {
+	int err;
+
 	if (!obj)
 		return -EINVAL;
 
@@ -931,18 +994,16 @@ int bpf_object__load(struct bpf_object *obj)
 	}
 
 	obj->loaded = true;
-	if (bpf_object__create_maps(obj))
-		goto out;
-	if (bpf_object__relocate(obj))
-		goto out;
-	if (bpf_object__load_progs(obj))
-		goto out;
+
+	CHECK_ERR(bpf_object__create_maps(obj), err, out);
+	CHECK_ERR(bpf_object__relocate(obj), err, out);
+	CHECK_ERR(bpf_object__load_progs(obj), err, out);
 
 	return 0;
 out:
 	bpf_object__unload(obj);
 	pr_warning("failed to load object '%s'\n", obj->path);
-	return -EINVAL;
+	return err;
 }
 
 void bpf_object__close(struct bpf_object *obj)
@@ -990,7 +1051,7 @@ const char *
 bpf_object__get_name(struct bpf_object *obj)
 {
 	if (!obj)
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	return obj->path;
 }
 
@@ -1043,7 +1104,7 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
 		title = strdup(title);
 		if (!title) {
 			pr_warning("failed to strdup program title\n");
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 		}
 	}
 
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index bc80af03c6f4..30a40e9fa503 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -10,6 +10,26 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <linux/err.h>
+
+enum libbpf_errno {
+	__LIBBPF_ERRNO__START = 4000,
+
+	/* Something wrong in libelf */
+	LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,
+	LIBBPF_ERRNO__FORMAT,	/* BPF object format invalid */
+	LIBBPF_ERRNO__KVERSION,	/* Incorrect or no 'version' section */
+	LIBBPF_ERRNO__ENDIAN,	/* Endian missmatch */
+	LIBBPF_ERRNO__INTERNAL,	/* Internal error in libbpf */
+	LIBBPF_ERRNO__RELOC,	/* Relocation failed */
+	LIBBPF_ERRNO__LOAD,	/* Load program failure for unknown reason */
+	LIBBPF_ERRNO__VERIFY,	/* Kernel verifier blocks program loading */
+	LIBBPF_ERRNO__PROG2BIG,	/* Program too big */
+	LIBBPF_ERRNO__KVER,	/* Incorrect kernel version */
+	__LIBBPF_ERRNO__END,
+};
+
+int libbpf_strerror(int err, char *buf, size_t size);
 
 /*
  * In include/linux/compiler-gcc.h, __printf is defined. However
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 512d3620e9f9..8f713f6d32f3 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -27,7 +27,7 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
 	struct bpf_object *obj;
 
 	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
-	if (!obj)
+	if (IS_ERR(obj))
 		return -1;
 	bpf_object__close(obj);
 	return 0;
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 0c5d174245bb..c46256b1f5fd 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -59,9 +59,9 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
 	} else
 		obj = bpf_object__open(filename);
 
-	if (!obj) {
+	if (IS_ERR(obj)) {
 		pr_debug("bpf: failed to load %s\n", filename);
-		return ERR_PTR(-EINVAL);
+		return obj;
 	}
 
 	return obj;
@@ -96,9 +96,9 @@ config_bpf_program(struct bpf_program *prog)
 	int err;
 
 	config_str = bpf_program__title(prog, false);
-	if (!config_str) {
+	if (IS_ERR(config_str)) {
 		pr_debug("bpf: unable to get title for program\n");
-		return -EINVAL;
+		return PTR_ERR(config_str);
 	}
 
 	priv = calloc(sizeof(*priv), 1);
@@ -308,13 +308,34 @@ int bpf__foreach_tev(struct bpf_object *obj,
 	return 0;
 }
 
+static int
+bpf_loader_strerror(int err, char *buf, size_t size)
+{
+	char sbuf[STRERR_BUFSIZE];
+	const char *msg;
+
+	if (!buf || !size)
+		return -1;
+
+	err = err > 0 ? err : -err;
+
+	if (err >= __LIBBPF_ERRNO__START)
+		return libbpf_strerror(err, buf, size);
+
+	msg = strerror_r(err, sbuf, sizeof(sbuf));
+	snprintf(buf, size, "%s", msg);
+	buf[size - 1] = '\0';
+	return 0;
+}
+
 #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));\
+	bpf_loader_strerror(err, sbuf, sizeof(sbuf));\
+	emsg = sbuf;\
 	switch (err) {\
 	default:\
 		scnprintf(buf, size, "%s", emsg);\
@@ -345,8 +366,6 @@ 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/parse-events.c b/tools/perf/util/parse-events.c
index bee60583839a..c75b25d5e28c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -632,11 +632,11 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
 	struct bpf_object *obj;
 
 	obj = bpf__prepare_load(bpf_file_name, source);
-	if (IS_ERR(obj) || !obj) {
+	if (IS_ERR(obj)) {
 		char errbuf[BUFSIZ];
 		int err;
 
-		err = obj ? PTR_ERR(obj) : -EINVAL;
+		err = PTR_ERR(obj);
 
 		if (err == -ENOTSUP)
 			snprintf(errbuf, sizeof(errbuf),
-- 
2.1.0


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

* [PATCH 05/11] bpf tools: Add new API bpf_object__get_kversion()
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (3 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 04/11] bpf tools: Improve libbpf error reporting Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 06/11] perf tools: Make fetch_kernel_version() publicly available Arnaldo Carvalho de Melo
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

bpf_object__get_kversion() can be used to fetch value of object's
'version' section. Following patch will use it for error reporting.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446817783-86722-3-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 8 ++++++++
 tools/lib/bpf/libbpf.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 07b492d3dfaa..e176bad19bcb 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1055,6 +1055,14 @@ bpf_object__get_name(struct bpf_object *obj)
 	return obj->path;
 }
 
+unsigned int
+bpf_object__get_kversion(struct bpf_object *obj)
+{
+	if (!obj)
+		return 0;
+	return obj->kern_version;
+}
+
 struct bpf_program *
 bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
 {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 30a40e9fa503..c9a9aef2806c 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -56,6 +56,7 @@ void bpf_object__close(struct bpf_object *object);
 int bpf_object__load(struct bpf_object *obj);
 int bpf_object__unload(struct bpf_object *obj);
 const char *bpf_object__get_name(struct bpf_object *obj);
+unsigned int bpf_object__get_kversion(struct bpf_object *obj);
 
 struct bpf_object *bpf_object__next(struct bpf_object *prev);
 #define bpf_object__for_each_safe(pos, tmp)			\
-- 
2.1.0


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

* [PATCH 06/11] perf tools: Make fetch_kernel_version() publicly available
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (4 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 05/11] bpf tools: Add new API bpf_object__get_kversion() Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 07/11] perf bpf: Improve BPF related error messages Arnaldo Carvalho de Melo
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

There are 2 places in llvm-utils.c which find kernel version information
through uname. This patch extracts the uname related code into a
fetch_kernel_version() function and puts it into util.h so it can be
reused.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446818135-87310-1-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/llvm-utils.c | 49 +++++++++++++++-----------------------------
 tools/perf/util/util.c       | 30 +++++++++++++++++++++++++++
 tools/perf/util/util.h       |  3 +++
 3 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 8ee25bea1b24..00724d496d38 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -4,7 +4,6 @@
  */
 
 #include <stdio.h>
-#include <sys/utsname.h>
 #include "util.h"
 #include "debug.h"
 #include "llvm-utils.h"
@@ -216,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir)
 	const char *suffix_dir = "";
 
 	char *autoconf_path;
-	struct utsname utsname;
 
 	int err;
 
 	if (!test_dir) {
-		err = uname(&utsname);
-		if (err) {
-			pr_warning("uname failed: %s\n", strerror(errno));
+		/* _UTSNAME_LENGTH is 65 */
+		char release[128];
+
+		err = fetch_kernel_version(NULL, release,
+					   sizeof(release));
+		if (err)
 			return -EINVAL;
-		}
 
-		test_dir = utsname.release;
+		test_dir = release;
 		prefix_dir = "/lib/modules/";
 		suffix_dir = "/build";
 	}
@@ -325,38 +325,18 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
 	pr_debug("include option is set to %s\n", *kbuild_include_opts);
 }
 
-static unsigned long
-fetch_kernel_version(void)
-{
-	struct utsname utsname;
-	int version, patchlevel, sublevel, err;
-
-	if (uname(&utsname))
-		return 0;
-
-	err = sscanf(utsname.release, "%d.%d.%d",
-		     &version, &patchlevel, &sublevel);
-
-	if (err != 3) {
-		pr_debug("Unablt to get kernel version from uname '%s'\n",
-			 utsname.release);
-		return 0;
-	}
-
-	return (version << 16) + (patchlevel << 8) + sublevel;
-}
-
 int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		      size_t *p_obj_buf_sz)
 {
+	size_t obj_buf_sz;
+	void *obj_buf = NULL;
 	int err, nr_cpus_avail;
-	char clang_path[PATH_MAX], nr_cpus_avail_str[64];
+	unsigned int kernel_version;
 	char linux_version_code_str[64];
 	const char *clang_opt = llvm_param.clang_opt;
-	const char *template = llvm_param.clang_bpf_cmd_template;
+	char clang_path[PATH_MAX], nr_cpus_avail_str[64];
 	char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
-	void *obj_buf = NULL;
-	size_t obj_buf_sz;
+	const char *template = llvm_param.clang_bpf_cmd_template;
 
 	if (!template)
 		template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
@@ -388,8 +368,11 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
 		 nr_cpus_avail);
 
+	if (fetch_kernel_version(&kernel_version, NULL, 0))
+		kernel_version = 0;
+
 	snprintf(linux_version_code_str, sizeof(linux_version_code_str),
-		 "0x%lx", fetch_kernel_version());
+		 "0x%x", kernel_version);
 
 	force_set_env("NR_CPUS", nr_cpus_avail_str);
 	force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index cd12c25e4ea4..47b1e36c7ea0 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -3,6 +3,7 @@
 #include "debug.h"
 #include <api/fs/fs.h>
 #include <sys/mman.h>
+#include <sys/utsname.h>
 #ifdef HAVE_BACKTRACE_SUPPORT
 #include <execinfo.h>
 #endif
@@ -665,3 +666,32 @@ bool find_process(const char *name)
 	closedir(dir);
 	return ret ? false : true;
 }
+
+int
+fetch_kernel_version(unsigned int *puint, char *str,
+		     size_t str_size)
+{
+	struct utsname utsname;
+	int version, patchlevel, sublevel, err;
+
+	if (uname(&utsname))
+		return -1;
+
+	if (str && str_size) {
+		strncpy(str, utsname.release, str_size);
+		str[str_size - 1] = '\0';
+	}
+
+	err = sscanf(utsname.release, "%d.%d.%d",
+		     &version, &patchlevel, &sublevel);
+
+	if (err != 3) {
+		pr_debug("Unablt to get kernel version from uname '%s'\n",
+			 utsname.release);
+		return -1;
+	}
+
+	if (puint)
+		*puint = (version << 16) + (patchlevel << 8) + sublevel;
+	return 0;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4cfb913aa9e0..2665126267dc 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -350,4 +350,7 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
 
 int get_stack_size(const char *str, unsigned long *_size);
 
+int fetch_kernel_version(unsigned int *puint,
+			 char *str, size_t str_sz);
+
 #endif /* GIT_COMPAT_UTIL_H */
-- 
2.1.0


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

* [PATCH 07/11] perf bpf: Improve BPF related error messages
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (5 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 06/11] perf tools: Make fetch_kernel_version() publicly available Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 08/11] perf test: Enhance the LLVM test: update basic BPF test program Arnaldo Carvalho de Melo
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

A series of bpf loader related error codes were introduced to help error
reporting. Functions were improved to return these new error codes.

Functions which return pointers were adjusted to encode error codes into
return value using the ERR_PTR() interface.

bpf_loader_strerror() was improved to convert these error messages to
strings. It checks the error codes and calls libbpf_strerror() and
strerror_r() accordingly, so caller don't need to consider checking the
range of the error code.

In bpf__strerror_load(), print kernel version of running kernel and the
object's 'version' section to notify user how to fix his/her program.

v1 -> v2:
 Use macro for error code.

 Fetch error message based on array index, eliminate for-loop.

 Print version strings.

Before:

  # perf record -e ./test_kversion_nomatch_program.o sleep 1
  event syntax error: './test_kversion_nomatch_program.o'
                       \___ Failed to load program: Validate your program and check 'license'/'version' sections in your object
  SKIP

  After:

  # perf record -e ./test_kversion_nomatch_program.o ls
  event syntax error: './test_kversion_nomatch_program.o'
                       \___ 'version' (4.4.0) doesn't match running kernel (4.3.0)
  SKIP

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446818289-87444-1-git-send-email-wangnan0@huawei.com
[ Add 'static inline' to bpf__strerror_prepare_load() when LIBBPF is disabled ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/bpf-loader.c   | 88 ++++++++++++++++++++++++++++++++++++------
 tools/perf/util/bpf-loader.h   | 23 +++++++++++
 tools/perf/util/parse-events.c |  7 ++--
 tools/perf/util/util.h         |  5 +++
 4 files changed, 108 insertions(+), 15 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index c46256b1f5fd..e3afa1b60bb5 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -53,7 +53,7 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
 
 		err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
 		if (err)
-			return ERR_PTR(err);
+			return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
 		obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
 		free(obj_buf);
 	} else
@@ -113,14 +113,14 @@ config_bpf_program(struct bpf_program *prog)
 	if (err < 0) {
 		pr_debug("bpf: '%s' is not a valid config string\n",
 			 config_str);
-		err = -EINVAL;
+		err = -BPF_LOADER_ERRNO__CONFIG;
 		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;
+		err = -BPF_LOADER_ERRNO__GROUP;
 		goto errout;
 	} else if (!pev->group)
 		pev->group = strdup(PERF_BPF_PROBE_GROUP);
@@ -132,9 +132,9 @@ config_bpf_program(struct bpf_program *prog)
 	}
 
 	if (!pev->event) {
-		pr_debug("bpf: '%s': event name is missing\n",
+		pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n",
 			 config_str);
-		err = -EINVAL;
+		err = -BPF_LOADER_ERRNO__EVENTNAME;
 		goto errout;
 	}
 	pr_debug("bpf: config '%s' is ok\n", config_str);
@@ -285,7 +285,7 @@ int bpf__foreach_tev(struct bpf_object *obj,
 				(void **)&priv);
 		if (err || !priv) {
 			pr_debug("bpf: failed to get private field\n");
-			return -EINVAL;
+			return -BPF_LOADER_ERRNO__INTERNAL;
 		}
 
 		pev = &priv->pev;
@@ -308,6 +308,18 @@ int bpf__foreach_tev(struct bpf_object *obj,
 	return 0;
 }
 
+#define ERRNO_OFFSET(e)		((e) - __BPF_LOADER_ERRNO__START)
+#define ERRCODE_OFFSET(c)	ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
+#define NR_ERRNO	(__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
+
+static const char *bpf_loader_strerror_table[NR_ERRNO] = {
+	[ERRCODE_OFFSET(CONFIG)]	= "Invalid config string",
+	[ERRCODE_OFFSET(GROUP)]		= "Invalid group name",
+	[ERRCODE_OFFSET(EVENTNAME)]	= "No event name found in config string",
+	[ERRCODE_OFFSET(INTERNAL)]	= "BPF loader internal error",
+	[ERRCODE_OFFSET(COMPILE)]	= "Error when compiling BPF scriptlet",
+};
+
 static int
 bpf_loader_strerror(int err, char *buf, size_t size)
 {
@@ -322,10 +334,21 @@ bpf_loader_strerror(int err, char *buf, size_t size)
 	if (err >= __LIBBPF_ERRNO__START)
 		return libbpf_strerror(err, buf, size);
 
-	msg = strerror_r(err, sbuf, sizeof(sbuf));
-	snprintf(buf, size, "%s", msg);
+	if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) {
+		msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)];
+		snprintf(buf, size, "%s", msg);
+		buf[size - 1] = '\0';
+		return 0;
+	}
+
+	if (err >= __BPF_LOADER_ERRNO__END)
+		snprintf(buf, size, "Unknown bpf loader error %d", err);
+	else
+		snprintf(buf, size, "%s",
+			 strerror_r(err, sbuf, sizeof(sbuf)));
+
 	buf[size - 1] = '\0';
-	return 0;
+	return -1;
 }
 
 #define bpf__strerror_head(err, buf, size) \
@@ -351,21 +374,62 @@ bpf_loader_strerror(int err, char *buf, size_t size)
 	}\
 	buf[size - 1] = '\0';
 
+int bpf__strerror_prepare_load(const char *filename, bool source,
+			       int err, char *buf, size_t size)
+{
+	size_t n;
+	int ret;
+
+	n = snprintf(buf, size, "Failed to load %s%s: ",
+			 filename, source ? " from source" : "");
+	if (n >= size) {
+		buf[size - 1] = '\0';
+		return 0;
+	}
+	buf += n;
+	size -= n;
+
+	ret = bpf_loader_strerror(err, buf, size);
+	buf[size - 1] = '\0';
+	return ret;
+}
+
 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_entry(EACCES, "You need to be root");
+	bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
+	bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
 	bpf__strerror_end(buf, size);
 	return 0;
 }
 
-int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
+int bpf__strerror_load(struct bpf_object *obj,
 		       int err, char *buf, size_t size)
 {
 	bpf__strerror_head(err, buf, size);
+	case LIBBPF_ERRNO__KVER: {
+		unsigned int obj_kver = bpf_object__get_kversion(obj);
+		unsigned int real_kver;
+
+		if (fetch_kernel_version(&real_kver, NULL, 0)) {
+			scnprintf(buf, size, "Unable to fetch kernel version");
+			break;
+		}
+
+		if (obj_kver != real_kver) {
+			scnprintf(buf, size,
+				  "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")",
+				  KVER_PARAM(obj_kver),
+				  KVER_PARAM(real_kver));
+			break;
+		}
+
+		scnprintf(buf, size, "Failed to load program for unknown reason");
+		break;
+	}
 	bpf__strerror_end(buf, size);
 	return 0;
 }
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index ccd8d7fd79d3..5eb3629eed8b 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,9 +8,21 @@
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <string.h>
+#include <bpf/libbpf.h>
 #include "probe-event.h"
 #include "debug.h"
 
+enum bpf_loader_errno {
+	__BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100,
+	/* Invalid config string */
+	BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START,
+	BPF_LOADER_ERRNO__GROUP,	/* Invalid group name */
+	BPF_LOADER_ERRNO__EVENTNAME,	/* Event name is missing */
+	BPF_LOADER_ERRNO__INTERNAL,	/* BPF loader internal error */
+	BPF_LOADER_ERRNO__COMPILE,	/* Error when compiling BPF scriptlet */
+	__BPF_LOADER_ERRNO__END,
+};
+
 struct bpf_object;
 #define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
 
@@ -19,6 +31,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);
+int bpf__strerror_prepare_load(const char *filename, bool source,
+			       int err, char *buf, size_t size);
 
 void bpf__clear(void);
 
@@ -67,6 +81,15 @@ __bpf_strerror(char *buf, size_t size)
 	return 0;
 }
 
+static inline
+int bpf__strerror_prepare_load(const char *filename __maybe_unused,
+			       bool source __maybe_unused,
+			       int err __maybe_unused,
+			       char *buf, size_t size)
+{
+	return __bpf_strerror(buf, size);
+}
+
 static inline int
 bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
 		    int err __maybe_unused,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c75b25d5e28c..e48d9da75707 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -642,9 +642,10 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
 			snprintf(errbuf, sizeof(errbuf),
 				 "BPF support is not compiled");
 		else
-			snprintf(errbuf, sizeof(errbuf),
-				 "BPF object file '%s' is invalid",
-				 bpf_file_name);
+			bpf__strerror_prepare_load(bpf_file_name,
+						   source,
+						   -err, errbuf,
+						   sizeof(errbuf));
 
 		data->error->help = strdup("(add -v to see detail)");
 		data->error->str = strdup(errbuf);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2665126267dc..dcc659017976 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -352,5 +352,10 @@ int get_stack_size(const char *str, unsigned long *_size);
 
 int fetch_kernel_version(unsigned int *puint,
 			 char *str, size_t str_sz);
+#define KVER_VERSION(x)		(((x) >> 16) & 0xff)
+#define KVER_PATCHLEVEL(x)	(((x) >> 8) & 0xff)
+#define KVER_SUBLEVEL(x)	((x) & 0xff)
+#define KVER_FMT	"%d.%d.%d"
+#define KVER_PARAM(x)	KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
 
 #endif /* GIT_COMPAT_UTIL_H */
-- 
2.1.0


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

* [PATCH 08/11] perf test: Enhance the LLVM test: update basic BPF test program
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (6 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 07/11] perf bpf: Improve BPF related error messages Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 09/11] perf test: Enhance the LLVM tests: add kbuild test Arnaldo Carvalho de Melo
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, He Kuang, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

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

The newly introduced BPF program attaches a BPF program to
'sys_epoll_pwait()'. perf itself never use that syscall, so further test
can verify their result with it. The program would generate 1 sample in
every 2 calls of epoll_pwait() system call.

Since the resulting BPF object is useful per se for further tests,
test_llvm__fetch_bpf_obj() is introduced for creating BPF objects from
source. The LLVM test was rewritten to use it.

Committer note:

Running it:

  [root@zoo wb]# perf test -v LLVM
  35: Test LLVM searching and compiling                        :
  --- start ---
  test child forked, pid 17740
  Kernel build dir is set to /lib/modules/4.3.0-rc1+/build
  set env: KBUILD_DIR=/lib/modules/4.3.0-rc1+/build
  unset env: KBUILD_OPTS
  include option is set to  -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated  -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
  set env: NR_CPUS=4
  set env: LINUX_VERSION_CODE=0x40300
  set env: CLANG_EXEC=/usr/libexec/icecc/bin/clang
  set env: CLANG_OPTIONS=-xc
  set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated  -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
  set env: WORKING_DIR=/lib/modules/4.3.0-rc1+/build
  set env: CLANG_SOURCE=-
  llvm compiling command template: echo '/*
   * 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'
  #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;
  ' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o -
  test child finished with 0
  ---- end ----
  Test LLVM searching and compiling: Ok
  [root@zoo wb]#

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446817783-86722-6-git-send-email-wangnan0@huawei.com
Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/Build                |   9 ++-
 tools/perf/tests/bpf-script-example.c |   4 ++
 tools/perf/tests/llvm.c               | 131 ++++++++++++++++++++++++++--------
 tools/perf/tests/llvm.h               |  16 +++++
 4 files changed, 129 insertions(+), 31 deletions(-)
 create mode 100644 tools/perf/tests/llvm.h

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 50de2253cff6..6c095b3d92a9 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,9 +31,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-base.o
 perf-y += topology.o
 
+$(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_base_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
index 410a70b93b93..0ec9c2c03164 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/llvm.c b/tools/perf/tests/llvm.c
index 8f713f6d32f3..05683c5f183e 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -2,6 +2,7 @@
 #include <bpf/libbpf.h>
 #include <util/llvm-utils.h>
 #include <util/cache.h>
+#include "llvm.h"
 #include "tests.h"
 #include "debug.h"
 
@@ -11,16 +12,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)
 {
@@ -28,25 +19,47 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
 
 	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
 	if (IS_ERR(obj))
-		return -1;
+		return TEST_FAIL;
 	bpf_object__close(obj);
-	return 0;
+	return TEST_OK;
 }
 #else
 static int test__bpf_parsing(void *obj_buf __maybe_unused,
 			     size_t obj_buf_sz __maybe_unused)
 {
 	pr_debug("Skip bpf parsing\n");
-	return 0;
+	return TEST_OK;
 }
 #endif
 
-int test__llvm(void)
+static struct {
+	const char *source;
+	const char *desc;
+} bpf_source_table[__LLVM_TESTCASE_MAX] = {
+	[LLVM_TESTCASE_BASE] = {
+		.source = test_llvm__bpf_base_prog,
+		.desc = "Basic BPF llvm compiling test",
+	},
+};
+
+
+int
+test_llvm__fetch_bpf_obj(void **p_obj_buf,
+			 size_t *p_obj_buf_sz,
+			 enum test_llvm__testcase index,
+			 bool force)
 {
-	char *tmpl_new, *clang_opt_new;
-	void *obj_buf;
-	size_t obj_buf_sz;
-	int err, old_verbose;
+	const char *source;
+	const char *desc;
+	const char *tmpl_old, *clang_opt_old;
+	char *tmpl_new = NULL, *clang_opt_new = NULL;
+	int err, old_verbose, ret = TEST_FAIL;
+
+	if (index >= __LLVM_TESTCASE_MAX)
+		return TEST_FAIL;
+
+	source = bpf_source_table[index].source;
+	desc = bpf_source_table[index].desc;
 
 	perf_config(perf_config_cb, NULL);
 
@@ -54,42 +67,100 @@ int test__llvm(void)
 	 * Skip this test if user's .perfconfig doesn't set [llvm] section
 	 * and clang is not found in $PATH, and this is not perf test -v
 	 */
-	if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) {
+	if (!force && (verbose == 0 &&
+		       !llvm_param.user_set_param &&
+		       llvm__search_clang())) {
 		pr_debug("No clang and no verbosive, skip this test\n");
 		return TEST_SKIP;
 	}
 
-	old_verbose = verbose;
 	/*
 	 * llvm is verbosity when error. Suppress all error output if
 	 * not 'perf test -v'.
 	 */
+	old_verbose = verbose;
 	if (verbose == 0)
 		verbose = -1;
 
+	*p_obj_buf = NULL;
+	*p_obj_buf_sz = 0;
+
 	if (!llvm_param.clang_bpf_cmd_template)
-		return -1;
+		goto out;
 
 	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);
+	err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
+		       llvm_param.clang_bpf_cmd_template,
+		       old_verbose ? "" : " 2>/dev/null");
 	if (err < 0)
-		return -1;
+		goto out;
 	err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
 	if (err < 0)
-		return -1;
+		goto out;
 
+	tmpl_old = llvm_param.clang_bpf_cmd_template;
 	llvm_param.clang_bpf_cmd_template = tmpl_new;
+	clang_opt_old = llvm_param.clang_opt;
 	llvm_param.clang_opt = clang_opt_new;
-	err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
+
+	err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz);
+
+	llvm_param.clang_bpf_cmd_template = tmpl_old;
+	llvm_param.clang_opt = clang_opt_old;
 
 	verbose = old_verbose;
 	if (err)
-		return TEST_FAIL;
+		goto out;
+
+	ret = TEST_OK;
+out:
+	free(tmpl_new);
+	free(clang_opt_new);
+	if (ret != TEST_OK)
+		pr_debug("Failed to compile test case: '%s'\n", desc);
+	return ret;
+}
 
-	err = test__bpf_parsing(obj_buf, obj_buf_sz);
-	free(obj_buf);
-	return err;
+int test__llvm(void)
+{
+	enum test_llvm__testcase i;
+
+	for (i = 0; i < __LLVM_TESTCASE_MAX; i++) {
+		int ret;
+		void *obj_buf = NULL;
+		size_t obj_buf_sz = 0;
+
+		ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+					       i, false);
+
+		if (ret == TEST_OK) {
+			ret = test__bpf_parsing(obj_buf, obj_buf_sz);
+			if (ret != TEST_OK)
+				pr_debug("Failed to parse test case '%s'\n",
+					 bpf_source_table[i].desc);
+		}
+		free(obj_buf);
+
+		switch (ret) {
+		case TEST_SKIP:
+			return TEST_SKIP;
+		case TEST_OK:
+			break;
+		default:
+			/*
+			 * Test 0 is the basic LLVM test. If test 0
+			 * fail, the basic LLVM support not functional
+			 * so the whole test should fail. If other test
+			 * case fail, it can be fixed by adjusting
+			 * config so don't report error.
+			 */
+			if (i == 0)
+				return TEST_FAIL;
+			else
+				return TEST_SKIP;
+		}
+	}
+	return TEST_OK;
 }
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 000000000000..bd63cee687b5
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,16 @@
+#ifndef PERF_TEST_LLVM_H
+#define PERF_TEST_LLVM_H
+
+#include <stddef.h> /* for size_t */
+#include <stdbool.h> /* for bool */
+
+extern const char test_llvm__bpf_base_prog[];
+
+enum test_llvm__testcase {
+	LLVM_TESTCASE_BASE,
+	__LLVM_TESTCASE_MAX,
+};
+
+int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
+			     enum test_llvm__testcase index, bool force);
+#endif
-- 
2.1.0


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

* [PATCH 09/11] perf test: Enhance the LLVM tests: add kbuild test
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (7 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 08/11] perf test: Enhance the LLVM test: update basic BPF test program Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 10/11] perf test: Add 'perf test BPF' Arnaldo Carvalho de Melo
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Jiri Olsa, Namhyung Kim, Zefan Li,
	pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

This patch adds a kbuild testcase to check whether kernel headers can be
correctly found.

For example:
  # mv /lib/modules/4.3.0-rc5{,.bak}
  # perf test LLVM

    38: Test LLVM searching and compiling                        : Skip

  # perf test -v LLVM
  ...
  <stdin>:11:10: fatal error: 'uapi/linux/fs.h' file not found
  #include <uapi/linux/fs.h>
          ^
  1 error generated.
  ERROR:	unable to compile -
  Hint:	Check error message shown above.
  Hint:	You can also pre-compile it into .o using:
     		 clang -target bpf -O2 -c -
	 with proper -I and -D options.
  Failed to compile test case: 'Test kbuild searching'
  test child finished with -2

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446817783-86722-7-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/Build                    |  9 ++++++++-
 tools/perf/tests/bpf-script-test-kbuild.c | 21 +++++++++++++++++++++
 tools/perf/tests/llvm.c                   |  4 ++++
 tools/perf/tests/llvm.h                   |  2 ++
 4 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 6c095b3d92a9..a47b21193fb2 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,7 +31,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
+perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
 perf-y += topology.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
@@ -41,6 +41,13 @@ $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
 	$(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 ';' >> $@
+
 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
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 000000000000..3626924740d8
--- /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(void *ctx)
+{
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 05683c5f183e..bc4cf507cde5 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -40,6 +40,10 @@ static struct {
 		.source = test_llvm__bpf_base_prog,
 		.desc = "Basic BPF llvm compiling test",
 	},
+	[LLVM_TESTCASE_KBUILD] = {
+		.source = test_llvm__bpf_test_kbuild_prog,
+		.desc = "Test kbuild searching",
+	},
 };
 
 
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index bd63cee687b5..d91d8f44efee 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -5,9 +5,11 @@
 #include <stdbool.h> /* for bool */
 
 extern const char test_llvm__bpf_base_prog[];
+extern const char test_llvm__bpf_test_kbuild_prog[];
 
 enum test_llvm__testcase {
 	LLVM_TESTCASE_BASE,
+	LLVM_TESTCASE_KBUILD,
 	__LLVM_TESTCASE_MAX,
 };
 
-- 
2.1.0


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

* [PATCH 10/11] perf test: Add 'perf test BPF'
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (8 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 09/11] perf test: Enhance the LLVM tests: add kbuild test Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-06 20:54 ` [PATCH 11/11] perf test: Do not be case sensitive when searching for matching tests Arnaldo Carvalho de Melo
  2015-11-08  7:24 ` [GIT PULL 00/11] perf/core improvements and fixes Ingo Molnar
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Wang Nan, Alexei Starovoitov, Jiri Olsa,
	Namhyung Kim, Zefan Li, pi3orama, Arnaldo Carvalho de Melo

From: Wang Nan <wangnan0@huawei.com>

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 its ability. The BPF script in 'perf test
LLVM' lets only 50% samples generated by epoll_pwait() to be captured.
This patch runs that system call for 111 times, so the result should
contain 56 samples.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1446817783-86722-8-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/Build          |   1 +
 tools/perf/tests/bpf.c          | 209 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c |   4 +
 tools/perf/tests/tests.h        |   1 +
 tools/perf/util/bpf-loader.c    |  24 ++++-
 tools/perf/util/bpf-loader.h    |  10 ++
 6 files changed, 248 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/tests/bpf.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index a47b21193fb2..f41ebf8849fe 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,6 +32,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-base.o llvm-src-kbuild.o
+perf-y += bpf.o
 perf-y += topology.o
 
 $(OUTPUT)tests/llvm-src-base.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 000000000000..ec16f7812c8b
--- /dev/null
+++ b/tools/perf/tests/bpf.c
@@ -0,0 +1,209 @@
+#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 {
+	enum test_llvm__testcase prog_id;
+	const char *desc;
+	const char *name;
+	const char *msg_compile_fail;
+	const char *msg_load_fail;
+	int (*target_func)(void);
+	int expect_result;
+} bpf_testcase_table[] = {
+	{
+		LLVM_TESTCASE_BASE,
+		"Test basic BPF filtering",
+		"[basic_bpf_test]",
+		"fix 'perf test LLVM' first",
+		"load bpf object failed",
+		&epoll_pwait_loop,
+		(NR_ITERS + 1) / 2,
+	},
+};
+
+static int do_test(struct bpf_object *obj, int (*func)(void),
+		   int expect)
+{
+	struct record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
+		.freq	      = 0,
+		.mmap_pages   = 256,
+		.default_interval = 1,
+	};
+
+	char pid[16];
+	char sbuf[STRERR_BUFSIZE];
+	struct perf_evlist *evlist;
+	int i, ret = TEST_FAIL, err = 0, count = 0;
+
+	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)) {
+		pr_debug("Failed to add events selected by BPF\n");
+		if (!err)
+			return TEST_FAIL;
+	}
+
+	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 TEST_FAIL;
+	}
+
+	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);
+	(*func)();
+	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 != expect)
+		pr_debug("BPF filter result incorrect\n");
+
+	ret = TEST_OK;
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	return ret;
+}
+
+static struct bpf_object *
+prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
+{
+	struct bpf_object *obj;
+
+	obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
+	if (IS_ERR(obj)) {
+		pr_debug("Compile BPF program failed.\n");
+		return NULL;
+	}
+	return obj;
+}
+
+static int __test__bpf(int index)
+{
+	int ret;
+	void *obj_buf;
+	size_t obj_buf_sz;
+	struct bpf_object *obj;
+
+	ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+				       bpf_testcase_table[index].prog_id,
+				       true);
+	if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
+		pr_debug("Unable to get BPF object, %s\n",
+			 bpf_testcase_table[index].msg_compile_fail);
+		if (index == 0)
+			return TEST_SKIP;
+		else
+			return TEST_FAIL;
+	}
+
+	obj = prepare_bpf(obj_buf, obj_buf_sz,
+			  bpf_testcase_table[index].name);
+	if (!obj) {
+		ret = TEST_FAIL;
+		goto out;
+	}
+
+	ret = do_test(obj,
+		      bpf_testcase_table[index].target_func,
+		      bpf_testcase_table[index].expect_result);
+out:
+	bpf__clear();
+	return ret;
+}
+
+int test__bpf(void)
+{
+	unsigned int i;
+	int err;
+
+	if (geteuid() != 0) {
+		pr_debug("Only root can run BPF test\n");
+		return TEST_SKIP;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) {
+		err = __test__bpf(i);
+
+		if (err != TEST_OK)
+			return err;
+	}
+
+	return TEST_OK;
+}
+
+#else
+int test__bpf(void)
+{
+	pr_debug("Skip BPF test because BPF support is not compiled\n");
+	return TEST_SKIP;
+}
+#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 66f72d3d6677..7b0120abc137 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -166,6 +166,10 @@ static struct test generic_tests[] = {
 		.func = test_session_topology,
 	},
 	{
+		.desc = "Test BPF filter",
+		.func = test__bpf,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c80486969f83..3c8734a3abbc 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -66,6 +66,7 @@ int test__fdarray__add(void);
 int test__kmod_path__parse(void);
 int test__thread_map(void);
 int test__llvm(void);
+int test__bpf(void);
 int test_session_topology(void);
 
 #if defined(__arm__) || defined(__aarch64__)
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index e3afa1b60bb5..4c50411371db 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -34,10 +34,32 @@ struct bpf_prog_priv {
 	struct perf_probe_event pev;
 };
 
+static bool libbpf_initialized;
+
+struct bpf_object *
+bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
+{
+	struct bpf_object *obj;
+
+	if (!libbpf_initialized) {
+		libbpf_set_print(libbpf_warning,
+				 libbpf_info,
+				 libbpf_debug);
+		libbpf_initialized = true;
+	}
+
+	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
+	if (IS_ERR(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;
-	static bool libbpf_initialized;
 
 	if (!libbpf_initialized) {
 		libbpf_set_print(libbpf_warning,
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 5eb3629eed8b..9caf3ae4acf3 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -34,6 +34,9 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source);
 int bpf__strerror_prepare_load(const char *filename, bool source,
 			       int err, char *buf, size_t size);
 
+struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
+					    const char *name);
+
 void bpf__clear(void);
 
 int bpf__probe(struct bpf_object *obj);
@@ -55,6 +58,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;}
-- 
2.1.0


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

* [PATCH 11/11] perf test: Do not be case sensitive when searching for matching tests
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (9 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 10/11] perf test: Add 'perf test BPF' Arnaldo Carvalho de Melo
@ 2015-11-06 20:54 ` Arnaldo Carvalho de Melo
  2015-11-08  7:24 ` [GIT PULL 00/11] perf/core improvements and fixes Ingo Molnar
  11 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-11-06 20:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Arnaldo Carvalho de Melo, Adrian Hunter,
	David Ahern, Jiri Olsa, Namhyung Kim, Wang Nan

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Before:

  # perf test llvm
  # perf test LLVM
  35: Test LLVM searching and compiling                        : Ok
  #

After

  # perf test llvm
  35: Test LLVM searching and compiling                        : Ok
  #

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-c1u05npqbf6epse17ovfejoj@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/builtin-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 7b0120abc137..80c442eab767 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -196,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
 			continue;
 		}
 
-		if (strstr(test->desc, argv[i]))
+		if (strcasestr(test->desc, argv[i]))
 			return true;
 	}
 
-- 
2.1.0


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

* Re: [GIT PULL 00/11] perf/core improvements and fixes
  2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
                   ` (10 preceding siblings ...)
  2015-11-06 20:54 ` [PATCH 11/11] perf test: Do not be case sensitive when searching for matching tests Arnaldo Carvalho de Melo
@ 2015-11-08  7:24 ` Ingo Molnar
  11 siblings, 0 replies; 13+ messages in thread
From: Ingo Molnar @ 2015-11-08  7:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, Adrian Hunter, Alexei Starovoitov, Andi Kleen,
	David Ahern, He Kuang, Jiri Olsa, Kan Liang, Masami Hiramatsu,
	Namhyung Kim, Peter Zijlstra, pi3orama, Wang Nan, Zefan Li,
	Arnaldo Carvalho de Melo


* Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> Hi Ingo,
> 
> 	Please consider pulling, this is on top of the perf-core-for-mingo tag,
> that is outstanding.
> 
> Best regards,
> 
> - Arnaldo
> 
> The following changes since commit 0014de172d228e450377d1fd079d94e67128d27f:
> 
>   perf sched latency: Fix thread pid reuse issue (2015-11-05 12:51:00 -0300)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo-2
> 
> for you to fetch changes up to 345c99a303e1d97b407bf99190314a878d59ca92:
> 
>   perf test: Do not be case sensitive when searching for matching tests (2015-11-06 17:50:04 -0300)
> 
> ----------------------------------------------------------------
> perf/core improvements and fixes:
> 
> - libbpf error reporting improvements, using a strerror interface to
>   more precisely tell the user about problems with the provided
>   scriptlet, be it in C or as a ready made object file (Wang Nan)
> 
> - Do not be case sensitive when searching for matching 'perf test'
>   entries (Arnaldo Carvalho de Melo)
> 
> - Inform the user about objdump failures in 'perf annotate' (Andi Kleen)
> 
> Infrastructure:
> 
> - Improve the LLVM 'perf test' entry, introduce new ones for
>   BPF and kbuild to check the environment used by clang to
>   compile .c scriptlets (Wang Nan)
> 
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> 
> ----------------------------------------------------------------
> Andi Kleen (1):
>       perf annotate: Inform the user about objdump failures in --stdio
> 
> Arnaldo Carvalho de Melo (1):
>       perf test: Do not be case sensitive when searching for matching tests
> 
> Jiri Olsa (1):
>       perf stat: Make stat options global
> 
> Masami Hiramatsu (1):
>       perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy
> 
> Wang Nan (7):
>       bpf tools: Improve libbpf error reporting
>       bpf tools: Add new API bpf_object__get_kversion()
>       perf tools: Make fetch_kernel_version() publicly available
>       perf bpf: Improve BPF related error messages
>       perf test: Enhance the LLVM test: update basic BPF test program
>       perf test: Enhance the LLVM tests: add kbuild test
>       perf test: Add 'perf test BPF'
> 
>  tools/lib/bpf/libbpf.c                    | 167 +++++++++++++++++-------
>  tools/lib/bpf/libbpf.h                    |  21 +++
>  tools/perf/builtin-stat.c                 | 163 +++++++++++------------
>  tools/perf/tests/Build                    |  17 ++-
>  tools/perf/tests/bpf-script-example.c     |   4 +
>  tools/perf/tests/bpf-script-test-kbuild.c |  21 +++
>  tools/perf/tests/bpf.c                    | 209 ++++++++++++++++++++++++++++++
>  tools/perf/tests/builtin-test.c           |   6 +-
>  tools/perf/tests/llvm.c                   | 137 +++++++++++++++-----
>  tools/perf/tests/llvm.h                   |  18 +++
>  tools/perf/tests/tests.h                  |   1 +
>  tools/perf/util/annotate.c                |  20 ++-
>  tools/perf/util/bpf-loader.c              | 139 +++++++++++++++++---
>  tools/perf/util/bpf-loader.h              |  33 +++++
>  tools/perf/util/llvm-utils.c              |  49 +++----
>  tools/perf/util/parse-events.c            |  11 +-
>  tools/perf/util/probe-event.c             |   7 +-
>  tools/perf/util/util.c                    |  30 +++++
>  tools/perf/util/util.h                    |   8 ++
>  19 files changed, 836 insertions(+), 225 deletions(-)
>  create mode 100644 tools/perf/tests/bpf-script-test-kbuild.c
>  create mode 100644 tools/perf/tests/bpf.c
>  create mode 100644 tools/perf/tests/llvm.h

Pulled into perf/urgent, thanks a lot Arnaldo!

	Ingo

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

end of thread, other threads:[~2015-11-08  7:24 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-06 20:54 [GIT PULL 00/11] perf/core improvements and fixes Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 01/11] perf stat: Make stat options global Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 02/11] perf annotate: Inform the user about objdump failures in --stdio Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 03/11] perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 04/11] bpf tools: Improve libbpf error reporting Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 05/11] bpf tools: Add new API bpf_object__get_kversion() Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 06/11] perf tools: Make fetch_kernel_version() publicly available Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 07/11] perf bpf: Improve BPF related error messages Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 08/11] perf test: Enhance the LLVM test: update basic BPF test program Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 09/11] perf test: Enhance the LLVM tests: add kbuild test Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 10/11] perf test: Add 'perf test BPF' Arnaldo Carvalho de Melo
2015-11-06 20:54 ` [PATCH 11/11] perf test: Do not be case sensitive when searching for matching tests Arnaldo Carvalho de Melo
2015-11-08  7:24 ` [GIT PULL 00/11] perf/core improvements and fixes Ingo Molnar

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).