perf/core improvements and fixes
Subsystems (3)
Arnaldo Carvalho de Melo
maintainerHi 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)
----------------------------------------------------------------
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
Arnaldo Carvalho de Melo
maintainerPATCH 1/11 perf stat: Make stat options global
From: Jiri Olsa <[email protected]>
So they can be used in perf stat record command in following patch.
--- tools/perf/builtin-stat.c | 163 +++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 81 deletions(-)
tools/perf/builtin-stat.c +82 -81
@@ -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. "
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 2/11 perf annotate: Inform the user about objdump failures in --stdio
In reply to Arnaldo Carvalho de MeloFrom: Andi Kleen <[email protected]>
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.
--- tools/perf/util/annotate.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
tools/perf/util/annotate.c +18 -2
@@ -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.
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 3/11 perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
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.
--- tools/perf/util/probe-event.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
tools/perf/util/probe-event.c +2 -5
@@ -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;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 4/11 bpf tools: Improve libbpf error reporting
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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
SKIPIn 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--- 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(-)
tools/lib/bpf/libbpf.c +110 -49
@@ -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 ); } }
tools/lib/bpf/libbpf.h +20 -0
@@ -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
tools/perf/tests/llvm.c +1 -1
@@ -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 ;
tools/perf/util/bpf-loader.c +26 -7
@@ -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 ; }
tools/perf/util/parse-events.c +2 -2
@@ -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),
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 5/11 bpf tools: Add new API bpf_object__get_kversion()
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
bpf_object__get_kversion() can be used to fetch value of object's 'version' section. Following patch will use it for error reporting.
--- tools/lib/bpf/libbpf.c | 8 ++++++++ tools/lib/bpf/libbpf.h | 1 + 2 files changed, 9 insertions(+)
tools/lib/bpf/libbpf.c +8 -0
@@ -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) {
tools/lib/bpf/libbpf.h +1 -0
@@ -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) \
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 6/11 perf tools: Make fetch_kernel_version() publicly available
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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.
--- 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(-)
tools/perf/util/llvm-utils.c +16 -33
@@ -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);
tools/perf/util/util.c +30 -0
@@ -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 ; +}
tools/perf/util/util.h +3 -0
@@ -350,4 +350,7 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, intint 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 */
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 7/11 perf bpf: Improve BPF related error messages
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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
SKIPAfter:
# 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--- 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(-)
tools/perf/util/bpf-loader.c +76 -12
@@ -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 ; }
tools/perf/util/bpf-loader.h +23 -0
@@ -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,
tools/perf/util/parse-events.c +4 -3
@@ -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);
tools/perf/util/util.h +5 -0
@@ -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 */
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 8/11 perf test: Enhance the LLVM test: update basic BPF test program
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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]#
--- 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
tools/perf/tests/Build +8 -1
@@ -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
tools/perf/tests/bpf-script-example.c +4 -0
@@ -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'
tools/perf/tests/llvm.c +101 -30
190 lines not on this page · raw message
tools/perf/tests/llvm.h new file +16 -0
@@ -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
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 9/11 perf test: Enhance the LLVM tests: add kbuild test
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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 LLVM38: 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--- 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
tools/perf/tests/Build +8 -1
@@ -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
tools/perf/tests/bpf-script-test-kbuild.c new file +21 -0
@@ -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;
tools/perf/tests/llvm.c +4 -0
@@ -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", + }, };
tools/perf/tests/llvm.h +2 -0
@@ -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, };
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 10/11 perf test: Add 'perf test BPF'
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
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.
--- 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
tools/perf/tests/Build +1 -0
@@ -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
tools/perf/tests/bpf.c new file +209 -0
209 lines not on this page · raw message
tools/perf/tests/builtin-test.c +4 -0
@@ -166,6 +166,10 @@ static struct test generic_tests[] = { .func = test_session_topology, }, { + .desc = "Test BPF filter", + .func = test__bpf, + }, + { .func = NULL, }, };
tools/perf/tests/tests.h +1 -0
@@ -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__)
tools/perf/util/bpf-loader.c +23 -1
@@ -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,
tools/perf/util/bpf-loader.h +10 -0
@@ -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 ;}
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 11/11 perf test: Do not be case sensitive when searching for matching tests
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
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 #
--- tools/perf/tests/builtin-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/builtin-test.c +1 -1
@@ -196,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const charcontinue ; } -if (strstr (test->desc, argv[i])) +if (strcasestr (test->desc, argv[i]))return true; }
Signature · 1 line
2.1.0
Quoted 78 lines · 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.gittags/perf-core-for-mingo-2for 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 <[email protected]>----------------------------------------------------------------
Andi Kleen (1):
perf annotate: Inform the user about objdump failures in --stdioArnaldo Carvalho de Melo (1):
perf test: Do not be case sensitive when searching for matching testsJiri Olsa (1):
perf stat: Make stat options globalMasami Hiramatsu (1):
perf probe: Cleanupfind_perf_probe_point_from_mapto reduce redundancyWang Nan (7):
bpf tools: Improve libbpf error reporting
bpf tools: Add new APIbpf_object__get_kversion()perf tools: Makefetch_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 +++----
Quoted 8 lines
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