diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-15 12:36:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-15 12:36:24 -0500 |
commit | 0ca9b67606f0ce984b5811b0830cfd7d143f6077 (patch) | |
tree | 0352af98e9760edd8bbd1712cd0c79f77156217a /tools/perf | |
parent | 051b29f2798b5f1a95e745613117eeb367ab4bce (diff) | |
parent | 41ac18ebfc429ce3f4d369ef07447d652999a0cd (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Thomas Gleixner:
"Mostly updates to the perf tool plus two fixes to the kernel core code:
- Handle tracepoint filters correctly for inherited events (Peter
Zijlstra)
- Prevent a deadlock in perf_lock_task_context (Paul McKenney)
- Add missing newlines to some pr_err() calls (Arnaldo Carvalho de
Melo)
- Print full source file paths when using 'perf annotate --print-line
--full-paths' (Michael Petlan)
- Fix 'perf probe -d' when just one out of uprobes and kprobes is
enabled (Wang Nan)
- Add compiler.h to list.h to fix 'make perf-tar-src-pkg' generated
tarballs, i.e. out of tree building (Arnaldo Carvalho de Melo)
- Add the llvm-src-base.c and llvm-src-kbuild.c files, generated by
the 'perf test' LLVM entries, when running it in-tree, to
.gitignore (Yunlong Song)
- 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)
- Improve the LLVM 'perf test' entry, introduce a new ones for BPF
and kbuild tests to check the environment used by clang to compile
.c scriptlets (Wang Nan)"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
perf/x86/intel/rapl: Remove the unused RAPL_EVENT_DESC() macro
tools include: Add compiler.h to list.h
perf probe: Verify parameters in two functions
perf session: Add missing newlines to some pr_err() calls
perf annotate: Support full source file paths for srcline fix
perf test: Add llvm-src-base.c and llvm-src-kbuild.c to .gitignore
perf: Fix inherited events vs. tracepoint filters
perf: Disable IRQs across RCU RS CS that acquires scheduler lock
perf test: Do not be case sensitive when searching for matching tests
perf test: Add 'perf test BPF'
perf test: Enhance the LLVM tests: add kbuild test
perf test: Enhance the LLVM test: update basic BPF test program
perf bpf: Improve BPF related error messages
perf tools: Make fetch_kernel_version() publicly available
bpf tools: Add new API bpf_object__get_kversion()
bpf tools: Improve libbpf error reporting
perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy
perf annotate: Inform the user about objdump failures in --stdio
perf stat: Make stat options global
perf sched latency: Fix thread pid reuse issue
...
Diffstat (limited to 'tools/perf')
30 files changed, 789 insertions, 224 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 7ea078658a87..13293de8869f 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -62,7 +62,6 @@ OPTIONS | |||
62 | --verbose=:: | 62 | --verbose=:: |
63 | Verbosity level. | 63 | Verbosity level. |
64 | 64 | ||
65 | -i:: | ||
66 | --no-inherit:: | 65 | --no-inherit:: |
67 | Child tasks do not inherit counters. | 66 | Child tasks do not inherit counters. |
68 | 67 | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 480546d5f13b..dcd9a70c7193 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -78,7 +78,7 @@ clean: | |||
78 | # The build-test target is not really parallel, don't print the jobs info: | 78 | # The build-test target is not really parallel, don't print the jobs info: |
79 | # | 79 | # |
80 | build-test: | 80 | build-test: |
81 | @$(MAKE) -f tests/make --no-print-directory | 81 | @$(MAKE) SHUF=1 -f tests/make --no-print-directory |
82 | 82 | ||
83 | # | 83 | # |
84 | # All other targets get passed through: | 84 | # All other targets get passed through: |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0ee6d900e100..e3d3e32c0a93 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1203,12 +1203,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1203 | 1203 | ||
1204 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1204 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
1205 | { | 1205 | { |
1206 | if (l->thread == r->thread) | ||
1207 | return 0; | ||
1206 | if (l->thread->tid < r->thread->tid) | 1208 | if (l->thread->tid < r->thread->tid) |
1207 | return -1; | 1209 | return -1; |
1208 | if (l->thread->tid > r->thread->tid) | 1210 | if (l->thread->tid > r->thread->tid) |
1209 | return 1; | 1211 | return 1; |
1210 | 1212 | return (int)(l->thread - r->thread); | |
1211 | return 0; | ||
1212 | } | 1213 | } |
1213 | 1214 | ||
1214 | static int avg_cmp(struct work_atoms *l, struct work_atoms *r) | 1215 | static int avg_cmp(struct work_atoms *l, struct work_atoms *r) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2f438f76cceb..e77880b5094d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -122,6 +122,9 @@ static bool forever = false; | |||
122 | static struct timespec ref_time; | 122 | static struct timespec ref_time; |
123 | static struct cpu_map *aggr_map; | 123 | static struct cpu_map *aggr_map; |
124 | static aggr_get_id_t aggr_get_id; | 124 | static aggr_get_id_t aggr_get_id; |
125 | static bool append_file; | ||
126 | static const char *output_name; | ||
127 | static int output_fd; | ||
125 | 128 | ||
126 | static volatile int done = 0; | 129 | static volatile int done = 0; |
127 | 130 | ||
@@ -513,15 +516,6 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) | |||
513 | 516 | ||
514 | if (evsel->cgrp) | 517 | if (evsel->cgrp) |
515 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 518 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
516 | |||
517 | if (csv_output || stat_config.interval) | ||
518 | return; | ||
519 | |||
520 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) | ||
521 | fprintf(output, " # %8.3f CPUs utilized ", | ||
522 | avg / avg_stats(&walltime_nsecs_stats)); | ||
523 | else | ||
524 | fprintf(output, " "); | ||
525 | } | 519 | } |
526 | 520 | ||
527 | static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) | 521 | static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) |
@@ -529,7 +523,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) | |||
529 | FILE *output = stat_config.output; | 523 | FILE *output = stat_config.output; |
530 | double sc = evsel->scale; | 524 | double sc = evsel->scale; |
531 | const char *fmt; | 525 | const char *fmt; |
532 | int cpu = cpu_map__id_to_cpu(id); | ||
533 | 526 | ||
534 | if (csv_output) { | 527 | if (csv_output) { |
535 | fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; | 528 | fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; |
@@ -542,9 +535,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) | |||
542 | 535 | ||
543 | aggr_printout(evsel, id, nr); | 536 | aggr_printout(evsel, id, nr); |
544 | 537 | ||
545 | if (stat_config.aggr_mode == AGGR_GLOBAL) | ||
546 | cpu = 0; | ||
547 | |||
548 | fprintf(output, fmt, avg, csv_sep); | 538 | fprintf(output, fmt, avg, csv_sep); |
549 | 539 | ||
550 | if (evsel->unit) | 540 | if (evsel->unit) |
@@ -556,12 +546,24 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) | |||
556 | 546 | ||
557 | if (evsel->cgrp) | 547 | if (evsel->cgrp) |
558 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 548 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
549 | } | ||
559 | 550 | ||
560 | if (csv_output || stat_config.interval) | 551 | static void printout(int id, int nr, struct perf_evsel *counter, double uval) |
561 | return; | 552 | { |
553 | int cpu = cpu_map__id_to_cpu(id); | ||
554 | |||
555 | if (stat_config.aggr_mode == AGGR_GLOBAL) | ||
556 | cpu = 0; | ||
562 | 557 | ||
563 | perf_stat__print_shadow_stats(output, evsel, avg, cpu, | 558 | if (nsec_counter(counter)) |
564 | stat_config.aggr_mode); | 559 | nsec_printout(id, nr, counter, uval); |
560 | else | ||
561 | abs_printout(id, nr, counter, uval); | ||
562 | |||
563 | if (!csv_output && !stat_config.interval) | ||
564 | perf_stat__print_shadow_stats(stat_config.output, counter, | ||
565 | uval, cpu, | ||
566 | stat_config.aggr_mode); | ||
565 | } | 567 | } |
566 | 568 | ||
567 | static void print_aggr(char *prefix) | 569 | static void print_aggr(char *prefix) |
@@ -617,12 +619,7 @@ static void print_aggr(char *prefix) | |||
617 | continue; | 619 | continue; |
618 | } | 620 | } |
619 | uval = val * counter->scale; | 621 | uval = val * counter->scale; |
620 | 622 | printout(id, nr, counter, uval); | |
621 | if (nsec_counter(counter)) | ||
622 | nsec_printout(id, nr, counter, uval); | ||
623 | else | ||
624 | abs_printout(id, nr, counter, uval); | ||
625 | |||
626 | if (!csv_output) | 623 | if (!csv_output) |
627 | print_noise(counter, 1.0); | 624 | print_noise(counter, 1.0); |
628 | 625 | ||
@@ -653,11 +650,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix) | |||
653 | fprintf(output, "%s", prefix); | 650 | fprintf(output, "%s", prefix); |
654 | 651 | ||
655 | uval = val * counter->scale; | 652 | uval = val * counter->scale; |
656 | 653 | printout(thread, 0, counter, uval); | |
657 | if (nsec_counter(counter)) | ||
658 | nsec_printout(thread, 0, counter, uval); | ||
659 | else | ||
660 | abs_printout(thread, 0, counter, uval); | ||
661 | 654 | ||
662 | if (!csv_output) | 655 | if (!csv_output) |
663 | print_noise(counter, 1.0); | 656 | print_noise(counter, 1.0); |
@@ -707,11 +700,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
707 | } | 700 | } |
708 | 701 | ||
709 | uval = avg * counter->scale; | 702 | uval = avg * counter->scale; |
710 | 703 | printout(-1, 0, counter, uval); | |
711 | if (nsec_counter(counter)) | ||
712 | nsec_printout(-1, 0, counter, uval); | ||
713 | else | ||
714 | abs_printout(-1, 0, counter, uval); | ||
715 | 704 | ||
716 | print_noise(counter, avg); | 705 | print_noise(counter, avg); |
717 | 706 | ||
@@ -764,12 +753,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
764 | } | 753 | } |
765 | 754 | ||
766 | uval = val * counter->scale; | 755 | uval = val * counter->scale; |
767 | 756 | printout(cpu, 0, counter, uval); | |
768 | if (nsec_counter(counter)) | ||
769 | nsec_printout(cpu, 0, counter, uval); | ||
770 | else | ||
771 | abs_printout(cpu, 0, counter, uval); | ||
772 | |||
773 | if (!csv_output) | 757 | if (!csv_output) |
774 | print_noise(counter, 1.0); | 758 | print_noise(counter, 1.0); |
775 | print_running(run, ena); | 759 | print_running(run, ena); |
@@ -946,6 +930,67 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, | |||
946 | return 0; | 930 | return 0; |
947 | } | 931 | } |
948 | 932 | ||
933 | static const struct option stat_options[] = { | ||
934 | OPT_BOOLEAN('T', "transaction", &transaction_run, | ||
935 | "hardware transaction statistics"), | ||
936 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
937 | "event selector. use 'perf list' to list available events", | ||
938 | parse_events_option), | ||
939 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
940 | "event filter", parse_filter), | ||
941 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
942 | "child tasks do not inherit counters"), | ||
943 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
944 | "stat events on existing process id"), | ||
945 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
946 | "stat events on existing thread id"), | ||
947 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
948 | "system-wide collection from all CPUs"), | ||
949 | OPT_BOOLEAN('g', "group", &group, | ||
950 | "put the counters into a counter group"), | ||
951 | OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), | ||
952 | OPT_INCR('v', "verbose", &verbose, | ||
953 | "be more verbose (show counter open errors, etc)"), | ||
954 | OPT_INTEGER('r', "repeat", &run_count, | ||
955 | "repeat command and print average + stddev (max: 100, forever: 0)"), | ||
956 | OPT_BOOLEAN('n', "null", &null_run, | ||
957 | "null run - dont start any counters"), | ||
958 | OPT_INCR('d', "detailed", &detailed_run, | ||
959 | "detailed run - start a lot of events"), | ||
960 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
961 | "call sync() before starting a run"), | ||
962 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
963 | "print large numbers with thousands\' separators", | ||
964 | stat__set_big_num), | ||
965 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
966 | "list of cpus to monitor in system-wide"), | ||
967 | OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, | ||
968 | "disable CPU count aggregation", AGGR_NONE), | ||
969 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
970 | "print counts with custom separator"), | ||
971 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
972 | "monitor event in cgroup name only", parse_cgroups), | ||
973 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | ||
974 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
975 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
976 | "log output to fd, instead of stderr"), | ||
977 | OPT_STRING(0, "pre", &pre_cmd, "command", | ||
978 | "command to run prior to the measured command"), | ||
979 | OPT_STRING(0, "post", &post_cmd, "command", | ||
980 | "command to run after to the measured command"), | ||
981 | OPT_UINTEGER('I', "interval-print", &stat_config.interval, | ||
982 | "print counts at regular interval in ms (>= 10)"), | ||
983 | OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, | ||
984 | "aggregate counts per processor socket", AGGR_SOCKET), | ||
985 | OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, | ||
986 | "aggregate counts per physical processor core", AGGR_CORE), | ||
987 | OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, | ||
988 | "aggregate counts per thread", AGGR_THREAD), | ||
989 | OPT_UINTEGER('D', "delay", &initial_delay, | ||
990 | "ms to wait before starting measurement after program start"), | ||
991 | OPT_END() | ||
992 | }; | ||
993 | |||
949 | static int perf_stat__get_socket(struct cpu_map *map, int cpu) | 994 | static int perf_stat__get_socket(struct cpu_map *map, int cpu) |
950 | { | 995 | { |
951 | return cpu_map__get_socket(map, cpu, NULL); | 996 | return cpu_map__get_socket(map, cpu, NULL); |
@@ -1193,69 +1238,6 @@ static int add_default_attributes(void) | |||
1193 | 1238 | ||
1194 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | 1239 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) |
1195 | { | 1240 | { |
1196 | bool append_file = false; | ||
1197 | int output_fd = 0; | ||
1198 | const char *output_name = NULL; | ||
1199 | const struct option options[] = { | ||
1200 | OPT_BOOLEAN('T', "transaction", &transaction_run, | ||
1201 | "hardware transaction statistics"), | ||
1202 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
1203 | "event selector. use 'perf list' to list available events", | ||
1204 | parse_events_option), | ||
1205 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
1206 | "event filter", parse_filter), | ||
1207 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
1208 | "child tasks do not inherit counters"), | ||
1209 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
1210 | "stat events on existing process id"), | ||
1211 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
1212 | "stat events on existing thread id"), | ||
1213 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
1214 | "system-wide collection from all CPUs"), | ||
1215 | OPT_BOOLEAN('g', "group", &group, | ||
1216 | "put the counters into a counter group"), | ||
1217 | OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), | ||
1218 | OPT_INCR('v', "verbose", &verbose, | ||
1219 | "be more verbose (show counter open errors, etc)"), | ||
1220 | OPT_INTEGER('r', "repeat", &run_count, | ||
1221 | "repeat command and print average + stddev (max: 100, forever: 0)"), | ||
1222 | OPT_BOOLEAN('n', "null", &null_run, | ||
1223 | "null run - dont start any counters"), | ||
1224 | OPT_INCR('d', "detailed", &detailed_run, | ||
1225 | "detailed run - start a lot of events"), | ||
1226 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
1227 | "call sync() before starting a run"), | ||
1228 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
1229 | "print large numbers with thousands\' separators", | ||
1230 | stat__set_big_num), | ||
1231 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
1232 | "list of cpus to monitor in system-wide"), | ||
1233 | OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, | ||
1234 | "disable CPU count aggregation", AGGR_NONE), | ||
1235 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
1236 | "print counts with custom separator"), | ||
1237 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
1238 | "monitor event in cgroup name only", parse_cgroups), | ||
1239 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | ||
1240 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
1241 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
1242 | "log output to fd, instead of stderr"), | ||
1243 | OPT_STRING(0, "pre", &pre_cmd, "command", | ||
1244 | "command to run prior to the measured command"), | ||
1245 | OPT_STRING(0, "post", &post_cmd, "command", | ||
1246 | "command to run after to the measured command"), | ||
1247 | OPT_UINTEGER('I', "interval-print", &stat_config.interval, | ||
1248 | "print counts at regular interval in ms (>= 10)"), | ||
1249 | OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, | ||
1250 | "aggregate counts per processor socket", AGGR_SOCKET), | ||
1251 | OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, | ||
1252 | "aggregate counts per physical processor core", AGGR_CORE), | ||
1253 | OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, | ||
1254 | "aggregate counts per thread", AGGR_THREAD), | ||
1255 | OPT_UINTEGER('D', "delay", &initial_delay, | ||
1256 | "ms to wait before starting measurement after program start"), | ||
1257 | OPT_END() | ||
1258 | }; | ||
1259 | const char * const stat_usage[] = { | 1241 | const char * const stat_usage[] = { |
1260 | "perf stat [<options>] [<command>]", | 1242 | "perf stat [<options>] [<command>]", |
1261 | NULL | 1243 | NULL |
@@ -1271,7 +1253,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1271 | if (evsel_list == NULL) | 1253 | if (evsel_list == NULL) |
1272 | return -ENOMEM; | 1254 | return -ENOMEM; |
1273 | 1255 | ||
1274 | argc = parse_options(argc, argv, options, stat_usage, | 1256 | argc = parse_options(argc, argv, stat_options, stat_usage, |
1275 | PARSE_OPT_STOP_AT_NON_OPTION); | 1257 | PARSE_OPT_STOP_AT_NON_OPTION); |
1276 | 1258 | ||
1277 | interval = stat_config.interval; | 1259 | interval = stat_config.interval; |
@@ -1281,14 +1263,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1281 | 1263 | ||
1282 | if (output_name && output_fd) { | 1264 | if (output_name && output_fd) { |
1283 | fprintf(stderr, "cannot use both --output and --log-fd\n"); | 1265 | fprintf(stderr, "cannot use both --output and --log-fd\n"); |
1284 | parse_options_usage(stat_usage, options, "o", 1); | 1266 | parse_options_usage(stat_usage, stat_options, "o", 1); |
1285 | parse_options_usage(NULL, options, "log-fd", 0); | 1267 | parse_options_usage(NULL, stat_options, "log-fd", 0); |
1286 | goto out; | 1268 | goto out; |
1287 | } | 1269 | } |
1288 | 1270 | ||
1289 | if (output_fd < 0) { | 1271 | if (output_fd < 0) { |
1290 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); | 1272 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); |
1291 | parse_options_usage(stat_usage, options, "log-fd", 0); | 1273 | parse_options_usage(stat_usage, stat_options, "log-fd", 0); |
1292 | goto out; | 1274 | goto out; |
1293 | } | 1275 | } |
1294 | 1276 | ||
@@ -1328,8 +1310,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1328 | /* User explicitly passed -B? */ | 1310 | /* User explicitly passed -B? */ |
1329 | if (big_num_opt == 1) { | 1311 | if (big_num_opt == 1) { |
1330 | fprintf(stderr, "-B option not supported with -x\n"); | 1312 | fprintf(stderr, "-B option not supported with -x\n"); |
1331 | parse_options_usage(stat_usage, options, "B", 1); | 1313 | parse_options_usage(stat_usage, stat_options, "B", 1); |
1332 | parse_options_usage(NULL, options, "x", 1); | 1314 | parse_options_usage(NULL, stat_options, "x", 1); |
1333 | goto out; | 1315 | goto out; |
1334 | } else /* Nope, so disable big number formatting */ | 1316 | } else /* Nope, so disable big number formatting */ |
1335 | big_num = false; | 1317 | big_num = false; |
@@ -1337,11 +1319,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1337 | big_num = false; | 1319 | big_num = false; |
1338 | 1320 | ||
1339 | if (!argc && target__none(&target)) | 1321 | if (!argc && target__none(&target)) |
1340 | usage_with_options(stat_usage, options); | 1322 | usage_with_options(stat_usage, stat_options); |
1341 | 1323 | ||
1342 | if (run_count < 0) { | 1324 | if (run_count < 0) { |
1343 | pr_err("Run count must be a positive number\n"); | 1325 | pr_err("Run count must be a positive number\n"); |
1344 | parse_options_usage(stat_usage, options, "r", 1); | 1326 | parse_options_usage(stat_usage, stat_options, "r", 1); |
1345 | goto out; | 1327 | goto out; |
1346 | } else if (run_count == 0) { | 1328 | } else if (run_count == 0) { |
1347 | forever = true; | 1329 | forever = true; |
@@ -1351,8 +1333,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1351 | if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { | 1333 | if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { |
1352 | fprintf(stderr, "The --per-thread option is only available " | 1334 | fprintf(stderr, "The --per-thread option is only available " |
1353 | "when monitoring via -p -t options.\n"); | 1335 | "when monitoring via -p -t options.\n"); |
1354 | parse_options_usage(NULL, options, "p", 1); | 1336 | parse_options_usage(NULL, stat_options, "p", 1); |
1355 | parse_options_usage(NULL, options, "t", 1); | 1337 | parse_options_usage(NULL, stat_options, "t", 1); |
1356 | goto out; | 1338 | goto out; |
1357 | } | 1339 | } |
1358 | 1340 | ||
@@ -1366,9 +1348,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1366 | fprintf(stderr, "both cgroup and no-aggregation " | 1348 | fprintf(stderr, "both cgroup and no-aggregation " |
1367 | "modes only available in system-wide mode\n"); | 1349 | "modes only available in system-wide mode\n"); |
1368 | 1350 | ||
1369 | parse_options_usage(stat_usage, options, "G", 1); | 1351 | parse_options_usage(stat_usage, stat_options, "G", 1); |
1370 | parse_options_usage(NULL, options, "A", 1); | 1352 | parse_options_usage(NULL, stat_options, "A", 1); |
1371 | parse_options_usage(NULL, options, "a", 1); | 1353 | parse_options_usage(NULL, stat_options, "a", 1); |
1372 | goto out; | 1354 | goto out; |
1373 | } | 1355 | } |
1374 | 1356 | ||
@@ -1380,12 +1362,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1380 | if (perf_evlist__create_maps(evsel_list, &target) < 0) { | 1362 | if (perf_evlist__create_maps(evsel_list, &target) < 0) { |
1381 | if (target__has_task(&target)) { | 1363 | if (target__has_task(&target)) { |
1382 | pr_err("Problems finding threads of monitor\n"); | 1364 | pr_err("Problems finding threads of monitor\n"); |
1383 | parse_options_usage(stat_usage, options, "p", 1); | 1365 | parse_options_usage(stat_usage, stat_options, "p", 1); |
1384 | parse_options_usage(NULL, options, "t", 1); | 1366 | parse_options_usage(NULL, stat_options, "t", 1); |
1385 | } else if (target__has_cpu(&target)) { | 1367 | } else if (target__has_cpu(&target)) { |
1386 | perror("failed to parse CPUs map"); | 1368 | perror("failed to parse CPUs map"); |
1387 | parse_options_usage(stat_usage, options, "C", 1); | 1369 | parse_options_usage(stat_usage, stat_options, "C", 1); |
1388 | parse_options_usage(NULL, options, "a", 1); | 1370 | parse_options_usage(NULL, stat_options, "a", 1); |
1389 | } | 1371 | } |
1390 | goto out; | 1372 | goto out; |
1391 | } | 1373 | } |
@@ -1400,7 +1382,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1400 | if (interval && interval < 100) { | 1382 | if (interval && interval < 100) { |
1401 | if (interval < 10) { | 1383 | if (interval < 10) { |
1402 | pr_err("print interval must be >= 10ms\n"); | 1384 | pr_err("print interval must be >= 10ms\n"); |
1403 | parse_options_usage(stat_usage, options, "I", 1); | 1385 | parse_options_usage(stat_usage, stat_options, "I", 1); |
1404 | goto out; | 1386 | goto out; |
1405 | } else | 1387 | } else |
1406 | pr_warning("print interval < 100ms. " | 1388 | pr_warning("print interval < 100ms. " |
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore new file mode 100644 index 000000000000..489fc9ffbcb0 --- /dev/null +++ b/tools/perf/tests/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | llvm-src-base.c | ||
2 | llvm-src-kbuild.c | ||
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 50de2253cff6..f41ebf8849fe 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -31,9 +31,24 @@ perf-y += sample-parsing.o | |||
31 | perf-y += parse-no-sample-id-all.o | 31 | perf-y += parse-no-sample-id-all.o |
32 | perf-y += kmod-path.o | 32 | perf-y += kmod-path.o |
33 | perf-y += thread-map.o | 33 | perf-y += thread-map.o |
34 | perf-y += llvm.o | 34 | perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o |
35 | perf-y += bpf.o | ||
35 | perf-y += topology.o | 36 | perf-y += topology.o |
36 | 37 | ||
38 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c | ||
39 | $(call rule_mkdir) | ||
40 | $(Q)echo '#include <tests/llvm.h>' > $@ | ||
41 | $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@ | ||
42 | $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ | ||
43 | $(Q)echo ';' >> $@ | ||
44 | |||
45 | $(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c | ||
46 | $(call rule_mkdir) | ||
47 | $(Q)echo '#include <tests/llvm.h>' > $@ | ||
48 | $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@ | ||
49 | $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ | ||
50 | $(Q)echo ';' >> $@ | ||
51 | |||
37 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) | 52 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) |
38 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o | 53 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o |
39 | endif | 54 | endif |
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 2dfc9ad0e6f2..638875a0960a 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
@@ -171,6 +171,5 @@ int test__attr(void) | |||
171 | !lstat(path_perf, &st)) | 171 | !lstat(path_perf, &st)) |
172 | return run_dir(path_dir, path_perf); | 172 | return run_dir(path_dir, path_perf); |
173 | 173 | ||
174 | fprintf(stderr, " (omitted)"); | 174 | return TEST_SKIP; |
175 | return 0; | ||
176 | } | 175 | } |
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 @@ | |||
1 | /* | ||
2 | * bpf-script-example.c | ||
3 | * Test basic LLVM building | ||
4 | */ | ||
1 | #ifndef LINUX_VERSION_CODE | 5 | #ifndef LINUX_VERSION_CODE |
2 | # error Need LINUX_VERSION_CODE | 6 | # error Need LINUX_VERSION_CODE |
3 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' | 7 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' |
diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c new file mode 100644 index 000000000000..3626924740d8 --- /dev/null +++ b/tools/perf/tests/bpf-script-test-kbuild.c | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * bpf-script-test-kbuild.c | ||
3 | * Test include from kernel header | ||
4 | */ | ||
5 | #ifndef LINUX_VERSION_CODE | ||
6 | # error Need LINUX_VERSION_CODE | ||
7 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' | ||
8 | #endif | ||
9 | #define SEC(NAME) __attribute__((section(NAME), used)) | ||
10 | |||
11 | #include <uapi/linux/fs.h> | ||
12 | #include <uapi/asm/ptrace.h> | ||
13 | |||
14 | SEC("func=vfs_llseek") | ||
15 | int bpf_func__vfs_llseek(void *ctx) | ||
16 | { | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | char _license[] SEC("license") = "GPL"; | ||
21 | int _version SEC("version") = LINUX_VERSION_CODE; | ||
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 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <sys/epoll.h> | ||
3 | #include <util/bpf-loader.h> | ||
4 | #include <util/evlist.h> | ||
5 | #include "tests.h" | ||
6 | #include "llvm.h" | ||
7 | #include "debug.h" | ||
8 | #define NR_ITERS 111 | ||
9 | |||
10 | #ifdef HAVE_LIBBPF_SUPPORT | ||
11 | |||
12 | static int epoll_pwait_loop(void) | ||
13 | { | ||
14 | int i; | ||
15 | |||
16 | /* Should fail NR_ITERS times */ | ||
17 | for (i = 0; i < NR_ITERS; i++) | ||
18 | epoll_pwait(-(i + 1), NULL, 0, 0, NULL); | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | static struct { | ||
23 | enum test_llvm__testcase prog_id; | ||
24 | const char *desc; | ||
25 | const char *name; | ||
26 | const char *msg_compile_fail; | ||
27 | const char *msg_load_fail; | ||
28 | int (*target_func)(void); | ||
29 | int expect_result; | ||
30 | } bpf_testcase_table[] = { | ||
31 | { | ||
32 | LLVM_TESTCASE_BASE, | ||
33 | "Test basic BPF filtering", | ||
34 | "[basic_bpf_test]", | ||
35 | "fix 'perf test LLVM' first", | ||
36 | "load bpf object failed", | ||
37 | &epoll_pwait_loop, | ||
38 | (NR_ITERS + 1) / 2, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static int do_test(struct bpf_object *obj, int (*func)(void), | ||
43 | int expect) | ||
44 | { | ||
45 | struct record_opts opts = { | ||
46 | .target = { | ||
47 | .uid = UINT_MAX, | ||
48 | .uses_mmap = true, | ||
49 | }, | ||
50 | .freq = 0, | ||
51 | .mmap_pages = 256, | ||
52 | .default_interval = 1, | ||
53 | }; | ||
54 | |||
55 | char pid[16]; | ||
56 | char sbuf[STRERR_BUFSIZE]; | ||
57 | struct perf_evlist *evlist; | ||
58 | int i, ret = TEST_FAIL, err = 0, count = 0; | ||
59 | |||
60 | struct parse_events_evlist parse_evlist; | ||
61 | struct parse_events_error parse_error; | ||
62 | |||
63 | bzero(&parse_error, sizeof(parse_error)); | ||
64 | bzero(&parse_evlist, sizeof(parse_evlist)); | ||
65 | parse_evlist.error = &parse_error; | ||
66 | INIT_LIST_HEAD(&parse_evlist.list); | ||
67 | |||
68 | err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj); | ||
69 | if (err || list_empty(&parse_evlist.list)) { | ||
70 | pr_debug("Failed to add events selected by BPF\n"); | ||
71 | if (!err) | ||
72 | return TEST_FAIL; | ||
73 | } | ||
74 | |||
75 | snprintf(pid, sizeof(pid), "%d", getpid()); | ||
76 | pid[sizeof(pid) - 1] = '\0'; | ||
77 | opts.target.tid = opts.target.pid = pid; | ||
78 | |||
79 | /* Instead of perf_evlist__new_default, don't add default events */ | ||
80 | evlist = perf_evlist__new(); | ||
81 | if (!evlist) { | ||
82 | pr_debug("No ehough memory to create evlist\n"); | ||
83 | return TEST_FAIL; | ||
84 | } | ||
85 | |||
86 | err = perf_evlist__create_maps(evlist, &opts.target); | ||
87 | if (err < 0) { | ||
88 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
89 | goto out_delete_evlist; | ||
90 | } | ||
91 | |||
92 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); | ||
93 | evlist->nr_groups = parse_evlist.nr_groups; | ||
94 | |||
95 | perf_evlist__config(evlist, &opts); | ||
96 | |||
97 | err = perf_evlist__open(evlist); | ||
98 | if (err < 0) { | ||
99 | pr_debug("perf_evlist__open: %s\n", | ||
100 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
101 | goto out_delete_evlist; | ||
102 | } | ||
103 | |||
104 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); | ||
105 | if (err < 0) { | ||
106 | pr_debug("perf_evlist__mmap: %s\n", | ||
107 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
108 | goto out_delete_evlist; | ||
109 | } | ||
110 | |||
111 | perf_evlist__enable(evlist); | ||
112 | (*func)(); | ||
113 | perf_evlist__disable(evlist); | ||
114 | |||
115 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
116 | union perf_event *event; | ||
117 | |||
118 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | ||
119 | const u32 type = event->header.type; | ||
120 | |||
121 | if (type == PERF_RECORD_SAMPLE) | ||
122 | count ++; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (count != expect) | ||
127 | pr_debug("BPF filter result incorrect\n"); | ||
128 | |||
129 | ret = TEST_OK; | ||
130 | |||
131 | out_delete_evlist: | ||
132 | perf_evlist__delete(evlist); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static struct bpf_object * | ||
137 | prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name) | ||
138 | { | ||
139 | struct bpf_object *obj; | ||
140 | |||
141 | obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name); | ||
142 | if (IS_ERR(obj)) { | ||
143 | pr_debug("Compile BPF program failed.\n"); | ||
144 | return NULL; | ||
145 | } | ||
146 | return obj; | ||
147 | } | ||
148 | |||
149 | static int __test__bpf(int index) | ||
150 | { | ||
151 | int ret; | ||
152 | void *obj_buf; | ||
153 | size_t obj_buf_sz; | ||
154 | struct bpf_object *obj; | ||
155 | |||
156 | ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, | ||
157 | bpf_testcase_table[index].prog_id, | ||
158 | true); | ||
159 | if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { | ||
160 | pr_debug("Unable to get BPF object, %s\n", | ||
161 | bpf_testcase_table[index].msg_compile_fail); | ||
162 | if (index == 0) | ||
163 | return TEST_SKIP; | ||
164 | else | ||
165 | return TEST_FAIL; | ||
166 | } | ||
167 | |||
168 | obj = prepare_bpf(obj_buf, obj_buf_sz, | ||
169 | bpf_testcase_table[index].name); | ||
170 | if (!obj) { | ||
171 | ret = TEST_FAIL; | ||
172 | goto out; | ||
173 | } | ||
174 | |||
175 | ret = do_test(obj, | ||
176 | bpf_testcase_table[index].target_func, | ||
177 | bpf_testcase_table[index].expect_result); | ||
178 | out: | ||
179 | bpf__clear(); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | int test__bpf(void) | ||
184 | { | ||
185 | unsigned int i; | ||
186 | int err; | ||
187 | |||
188 | if (geteuid() != 0) { | ||
189 | pr_debug("Only root can run BPF test\n"); | ||
190 | return TEST_SKIP; | ||
191 | } | ||
192 | |||
193 | for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) { | ||
194 | err = __test__bpf(i); | ||
195 | |||
196 | if (err != TEST_OK) | ||
197 | return err; | ||
198 | } | ||
199 | |||
200 | return TEST_OK; | ||
201 | } | ||
202 | |||
203 | #else | ||
204 | int test__bpf(void) | ||
205 | { | ||
206 | pr_debug("Skip BPF test because BPF support is not compiled\n"); | ||
207 | return TEST_SKIP; | ||
208 | } | ||
209 | #endif | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 66f72d3d6677..80c442eab767 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -166,6 +166,10 @@ static struct test generic_tests[] = { | |||
166 | .func = test_session_topology, | 166 | .func = test_session_topology, |
167 | }, | 167 | }, |
168 | { | 168 | { |
169 | .desc = "Test BPF filter", | ||
170 | .func = test__bpf, | ||
171 | }, | ||
172 | { | ||
169 | .func = NULL, | 173 | .func = NULL, |
170 | }, | 174 | }, |
171 | }; | 175 | }; |
@@ -192,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char | |||
192 | continue; | 196 | continue; |
193 | } | 197 | } |
194 | 198 | ||
195 | if (strstr(test->desc, argv[i])) | 199 | if (strcasestr(test->desc, argv[i])) |
196 | return true; | 200 | return true; |
197 | } | 201 | } |
198 | 202 | ||
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 49b1959dda41..a767a6400c5c 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -613,16 +613,16 @@ int test__code_reading(void) | |||
613 | case TEST_CODE_READING_OK: | 613 | case TEST_CODE_READING_OK: |
614 | return 0; | 614 | return 0; |
615 | case TEST_CODE_READING_NO_VMLINUX: | 615 | case TEST_CODE_READING_NO_VMLINUX: |
616 | fprintf(stderr, " (no vmlinux)"); | 616 | pr_debug("no vmlinux\n"); |
617 | return 0; | 617 | return 0; |
618 | case TEST_CODE_READING_NO_KCORE: | 618 | case TEST_CODE_READING_NO_KCORE: |
619 | fprintf(stderr, " (no kcore)"); | 619 | pr_debug("no kcore\n"); |
620 | return 0; | 620 | return 0; |
621 | case TEST_CODE_READING_NO_ACCESS: | 621 | case TEST_CODE_READING_NO_ACCESS: |
622 | fprintf(stderr, " (no access)"); | 622 | pr_debug("no access\n"); |
623 | return 0; | 623 | return 0; |
624 | case TEST_CODE_READING_NO_KERNEL_OBJ: | 624 | case TEST_CODE_READING_NO_KERNEL_OBJ: |
625 | fprintf(stderr, " (no kernel obj)"); | 625 | pr_debug("no kernel obj\n"); |
626 | return 0; | 626 | return 0; |
627 | default: | 627 | default: |
628 | return -1; | 628 | return -1; |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 4d4b9837b630..a2e2269aa093 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
@@ -90,8 +90,8 @@ int test__keep_tracking(void) | |||
90 | evsel->attr.enable_on_exec = 0; | 90 | evsel->attr.enable_on_exec = 0; |
91 | 91 | ||
92 | if (perf_evlist__open(evlist) < 0) { | 92 | if (perf_evlist__open(evlist) < 0) { |
93 | fprintf(stderr, " (not supported)"); | 93 | pr_debug("Unable to open dummy and cycles event\n"); |
94 | err = 0; | 94 | err = TEST_SKIP; |
95 | goto out_err; | 95 | goto out_err; |
96 | } | 96 | } |
97 | 97 | ||
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index 52d55971f66f..bc4cf507cde5 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <bpf/libbpf.h> | 2 | #include <bpf/libbpf.h> |
3 | #include <util/llvm-utils.h> | 3 | #include <util/llvm-utils.h> |
4 | #include <util/cache.h> | 4 | #include <util/cache.h> |
5 | #include "llvm.h" | ||
5 | #include "tests.h" | 6 | #include "tests.h" |
6 | #include "debug.h" | 7 | #include "debug.h" |
7 | 8 | ||
@@ -11,42 +12,58 @@ static int perf_config_cb(const char *var, const char *val, | |||
11 | return perf_default_config(var, val, arg); | 12 | return perf_default_config(var, val, arg); |
12 | } | 13 | } |
13 | 14 | ||
14 | /* | ||
15 | * Randomly give it a "version" section since we don't really load it | ||
16 | * into kernel | ||
17 | */ | ||
18 | static const char test_bpf_prog[] = | ||
19 | "__attribute__((section(\"do_fork\"), used)) " | ||
20 | "int fork(void *ctx) {return 0;} " | ||
21 | "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";" | ||
22 | "int _version __attribute__((section(\"version\"), used)) = 0x40100;"; | ||
23 | |||
24 | #ifdef HAVE_LIBBPF_SUPPORT | 15 | #ifdef HAVE_LIBBPF_SUPPORT |
25 | static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) | 16 | static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) |
26 | { | 17 | { |
27 | struct bpf_object *obj; | 18 | struct bpf_object *obj; |
28 | 19 | ||
29 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); | 20 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); |
30 | if (!obj) | 21 | if (IS_ERR(obj)) |
31 | return -1; | 22 | return TEST_FAIL; |
32 | bpf_object__close(obj); | 23 | bpf_object__close(obj); |
33 | return 0; | 24 | return TEST_OK; |
34 | } | 25 | } |
35 | #else | 26 | #else |
36 | static int test__bpf_parsing(void *obj_buf __maybe_unused, | 27 | static int test__bpf_parsing(void *obj_buf __maybe_unused, |
37 | size_t obj_buf_sz __maybe_unused) | 28 | size_t obj_buf_sz __maybe_unused) |
38 | { | 29 | { |
39 | fprintf(stderr, " (skip bpf parsing)"); | 30 | pr_debug("Skip bpf parsing\n"); |
40 | return 0; | 31 | return TEST_OK; |
41 | } | 32 | } |
42 | #endif | 33 | #endif |
43 | 34 | ||
44 | int test__llvm(void) | 35 | static struct { |
36 | const char *source; | ||
37 | const char *desc; | ||
38 | } bpf_source_table[__LLVM_TESTCASE_MAX] = { | ||
39 | [LLVM_TESTCASE_BASE] = { | ||
40 | .source = test_llvm__bpf_base_prog, | ||
41 | .desc = "Basic BPF llvm compiling test", | ||
42 | }, | ||
43 | [LLVM_TESTCASE_KBUILD] = { | ||
44 | .source = test_llvm__bpf_test_kbuild_prog, | ||
45 | .desc = "Test kbuild searching", | ||
46 | }, | ||
47 | }; | ||
48 | |||
49 | |||
50 | int | ||
51 | test_llvm__fetch_bpf_obj(void **p_obj_buf, | ||
52 | size_t *p_obj_buf_sz, | ||
53 | enum test_llvm__testcase index, | ||
54 | bool force) | ||
45 | { | 55 | { |
46 | char *tmpl_new, *clang_opt_new; | 56 | const char *source; |
47 | void *obj_buf; | 57 | const char *desc; |
48 | size_t obj_buf_sz; | 58 | const char *tmpl_old, *clang_opt_old; |
49 | int err, old_verbose; | 59 | char *tmpl_new = NULL, *clang_opt_new = NULL; |
60 | int err, old_verbose, ret = TEST_FAIL; | ||
61 | |||
62 | if (index >= __LLVM_TESTCASE_MAX) | ||
63 | return TEST_FAIL; | ||
64 | |||
65 | source = bpf_source_table[index].source; | ||
66 | desc = bpf_source_table[index].desc; | ||
50 | 67 | ||
51 | perf_config(perf_config_cb, NULL); | 68 | perf_config(perf_config_cb, NULL); |
52 | 69 | ||
@@ -54,45 +71,100 @@ int test__llvm(void) | |||
54 | * Skip this test if user's .perfconfig doesn't set [llvm] section | 71 | * Skip this test if user's .perfconfig doesn't set [llvm] section |
55 | * and clang is not found in $PATH, and this is not perf test -v | 72 | * and clang is not found in $PATH, and this is not perf test -v |
56 | */ | 73 | */ |
57 | if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { | 74 | if (!force && (verbose == 0 && |
58 | fprintf(stderr, " (no clang, try 'perf test -v LLVM')"); | 75 | !llvm_param.user_set_param && |
76 | llvm__search_clang())) { | ||
77 | pr_debug("No clang and no verbosive, skip this test\n"); | ||
59 | return TEST_SKIP; | 78 | return TEST_SKIP; |
60 | } | 79 | } |
61 | 80 | ||
62 | old_verbose = verbose; | ||
63 | /* | 81 | /* |
64 | * llvm is verbosity when error. Suppress all error output if | 82 | * llvm is verbosity when error. Suppress all error output if |
65 | * not 'perf test -v'. | 83 | * not 'perf test -v'. |
66 | */ | 84 | */ |
85 | old_verbose = verbose; | ||
67 | if (verbose == 0) | 86 | if (verbose == 0) |
68 | verbose = -1; | 87 | verbose = -1; |
69 | 88 | ||
89 | *p_obj_buf = NULL; | ||
90 | *p_obj_buf_sz = 0; | ||
91 | |||
70 | if (!llvm_param.clang_bpf_cmd_template) | 92 | if (!llvm_param.clang_bpf_cmd_template) |
71 | return -1; | 93 | goto out; |
72 | 94 | ||
73 | if (!llvm_param.clang_opt) | 95 | if (!llvm_param.clang_opt) |
74 | llvm_param.clang_opt = strdup(""); | 96 | llvm_param.clang_opt = strdup(""); |
75 | 97 | ||
76 | err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, | 98 | err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, |
77 | llvm_param.clang_bpf_cmd_template); | 99 | llvm_param.clang_bpf_cmd_template, |
100 | old_verbose ? "" : " 2>/dev/null"); | ||
78 | if (err < 0) | 101 | if (err < 0) |
79 | return -1; | 102 | goto out; |
80 | err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); | 103 | err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); |
81 | if (err < 0) | 104 | if (err < 0) |
82 | return -1; | 105 | goto out; |
83 | 106 | ||
107 | tmpl_old = llvm_param.clang_bpf_cmd_template; | ||
84 | llvm_param.clang_bpf_cmd_template = tmpl_new; | 108 | llvm_param.clang_bpf_cmd_template = tmpl_new; |
109 | clang_opt_old = llvm_param.clang_opt; | ||
85 | llvm_param.clang_opt = clang_opt_new; | 110 | llvm_param.clang_opt = clang_opt_new; |
86 | err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz); | 111 | |
112 | err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz); | ||
113 | |||
114 | llvm_param.clang_bpf_cmd_template = tmpl_old; | ||
115 | llvm_param.clang_opt = clang_opt_old; | ||
87 | 116 | ||
88 | verbose = old_verbose; | 117 | verbose = old_verbose; |
89 | if (err) { | 118 | if (err) |
90 | if (!verbose) | 119 | goto out; |
91 | fprintf(stderr, " (use -v to see error message)"); | 120 | |
92 | return -1; | 121 | ret = TEST_OK; |
93 | } | 122 | out: |
123 | free(tmpl_new); | ||
124 | free(clang_opt_new); | ||
125 | if (ret != TEST_OK) | ||
126 | pr_debug("Failed to compile test case: '%s'\n", desc); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | int test__llvm(void) | ||
131 | { | ||
132 | enum test_llvm__testcase i; | ||
133 | |||
134 | for (i = 0; i < __LLVM_TESTCASE_MAX; i++) { | ||
135 | int ret; | ||
136 | void *obj_buf = NULL; | ||
137 | size_t obj_buf_sz = 0; | ||
138 | |||
139 | ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, | ||
140 | i, false); | ||
94 | 141 | ||
95 | err = test__bpf_parsing(obj_buf, obj_buf_sz); | 142 | if (ret == TEST_OK) { |
96 | free(obj_buf); | 143 | ret = test__bpf_parsing(obj_buf, obj_buf_sz); |
97 | return err; | 144 | if (ret != TEST_OK) |
145 | pr_debug("Failed to parse test case '%s'\n", | ||
146 | bpf_source_table[i].desc); | ||
147 | } | ||
148 | free(obj_buf); | ||
149 | |||
150 | switch (ret) { | ||
151 | case TEST_SKIP: | ||
152 | return TEST_SKIP; | ||
153 | case TEST_OK: | ||
154 | break; | ||
155 | default: | ||
156 | /* | ||
157 | * Test 0 is the basic LLVM test. If test 0 | ||
158 | * fail, the basic LLVM support not functional | ||
159 | * so the whole test should fail. If other test | ||
160 | * case fail, it can be fixed by adjusting | ||
161 | * config so don't report error. | ||
162 | */ | ||
163 | if (i == 0) | ||
164 | return TEST_FAIL; | ||
165 | else | ||
166 | return TEST_SKIP; | ||
167 | } | ||
168 | } | ||
169 | return TEST_OK; | ||
98 | } | 170 | } |
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h new file mode 100644 index 000000000000..d91d8f44efee --- /dev/null +++ b/tools/perf/tests/llvm.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef PERF_TEST_LLVM_H | ||
2 | #define PERF_TEST_LLVM_H | ||
3 | |||
4 | #include <stddef.h> /* for size_t */ | ||
5 | #include <stdbool.h> /* for bool */ | ||
6 | |||
7 | extern const char test_llvm__bpf_base_prog[]; | ||
8 | extern const char test_llvm__bpf_test_kbuild_prog[]; | ||
9 | |||
10 | enum test_llvm__testcase { | ||
11 | LLVM_TESTCASE_BASE, | ||
12 | LLVM_TESTCASE_KBUILD, | ||
13 | __LLVM_TESTCASE_MAX, | ||
14 | }; | ||
15 | |||
16 | int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, | ||
17 | enum test_llvm__testcase index, bool force); | ||
18 | #endif | ||
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 2cbd0c6901e3..8ea3dffc5065 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -221,6 +221,11 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O)) | |||
221 | 221 | ||
222 | all: | 222 | all: |
223 | 223 | ||
224 | ifdef SHUF | ||
225 | run := $(shell shuf -e $(run)) | ||
226 | run_O := $(shell shuf -e $(run_O)) | ||
227 | endif | ||
228 | |||
224 | ifdef DEBUG | 229 | ifdef DEBUG |
225 | d := $(info run $(run)) | 230 | d := $(info run $(run)) |
226 | d := $(info run_O $(run_O)) | 231 | d := $(info run_O $(run_O)) |
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index e698742d4fec..a02af503100c 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c | |||
@@ -366,7 +366,7 @@ int test__switch_tracking(void) | |||
366 | 366 | ||
367 | /* Third event */ | 367 | /* Third event */ |
368 | if (!perf_evlist__can_select_event(evlist, sched_switch)) { | 368 | if (!perf_evlist__can_select_event(evlist, sched_switch)) { |
369 | fprintf(stderr, " (no sched_switch)"); | 369 | pr_debug("No sched_switch\n"); |
370 | err = 0; | 370 | err = 0; |
371 | goto out; | 371 | goto out; |
372 | } | 372 | } |
@@ -442,7 +442,7 @@ int test__switch_tracking(void) | |||
442 | } | 442 | } |
443 | 443 | ||
444 | if (perf_evlist__open(evlist) < 0) { | 444 | if (perf_evlist__open(evlist) < 0) { |
445 | fprintf(stderr, " (not supported)"); | 445 | pr_debug("Not supported\n"); |
446 | err = 0; | 446 | err = 0; |
447 | goto out; | 447 | goto out; |
448 | } | 448 | } |
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); | |||
66 | int test__kmod_path__parse(void); | 66 | int test__kmod_path__parse(void); |
67 | int test__thread_map(void); | 67 | int test__thread_map(void); |
68 | int test__llvm(void); | 68 | int test__llvm(void); |
69 | int test__bpf(void); | ||
69 | int test_session_topology(void); | 70 | int test_session_topology(void); |
70 | 71 | ||
71 | #if defined(__arm__) || defined(__aarch64__) | 72 | #if defined(__arm__) || defined(__aarch64__) |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0fc8d7a2fea5..1dd1949b0e79 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) | |||
1084 | struct kcore_extract kce; | 1084 | struct kcore_extract kce; |
1085 | bool delete_extract = false; | 1085 | bool delete_extract = false; |
1086 | int lineno = 0; | 1086 | int lineno = 0; |
1087 | int nline; | ||
1087 | 1088 | ||
1088 | if (filename) | 1089 | if (filename) |
1089 | symbol__join_symfs(symfs_filename, filename); | 1090 | symbol__join_symfs(symfs_filename, filename); |
@@ -1179,6 +1180,9 @@ fallback: | |||
1179 | 1180 | ||
1180 | ret = decompress_to_file(m.ext, symfs_filename, fd); | 1181 | ret = decompress_to_file(m.ext, symfs_filename, fd); |
1181 | 1182 | ||
1183 | if (ret) | ||
1184 | pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename); | ||
1185 | |||
1182 | free(m.ext); | 1186 | free(m.ext); |
1183 | close(fd); | 1187 | close(fd); |
1184 | 1188 | ||
@@ -1204,13 +1208,25 @@ fallback: | |||
1204 | pr_debug("Executing: %s\n", command); | 1208 | pr_debug("Executing: %s\n", command); |
1205 | 1209 | ||
1206 | file = popen(command, "r"); | 1210 | file = popen(command, "r"); |
1207 | if (!file) | 1211 | if (!file) { |
1212 | pr_err("Failure running %s\n", command); | ||
1213 | /* | ||
1214 | * If we were using debug info should retry with | ||
1215 | * original binary. | ||
1216 | */ | ||
1208 | goto out_remove_tmp; | 1217 | goto out_remove_tmp; |
1218 | } | ||
1209 | 1219 | ||
1210 | while (!feof(file)) | 1220 | nline = 0; |
1221 | while (!feof(file)) { | ||
1211 | if (symbol__parse_objdump_line(sym, map, file, privsize, | 1222 | if (symbol__parse_objdump_line(sym, map, file, privsize, |
1212 | &lineno) < 0) | 1223 | &lineno) < 0) |
1213 | break; | 1224 | break; |
1225 | nline++; | ||
1226 | } | ||
1227 | |||
1228 | if (nline == 0) | ||
1229 | pr_err("No output from %s\n", command); | ||
1214 | 1230 | ||
1215 | /* | 1231 | /* |
1216 | * kallsyms does not have symbol sizes so there may a nop at the end. | 1232 | * kallsyms does not have symbol sizes so there may a nop at the end. |
@@ -1604,6 +1620,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1604 | len = symbol__size(sym); | 1620 | len = symbol__size(sym); |
1605 | 1621 | ||
1606 | if (print_lines) { | 1622 | if (print_lines) { |
1623 | srcline_full_filename = full_paths; | ||
1607 | symbol__get_source_line(sym, map, evsel, &source_line, len); | 1624 | symbol__get_source_line(sym, map, evsel, &source_line, len); |
1608 | print_summary(&source_line, dso->long_name); | 1625 | print_summary(&source_line, dso->long_name); |
1609 | } | 1626 | } |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index ba6f7526b282..4c50411371db 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -26,18 +26,40 @@ static int libbpf_##name(const char *fmt, ...) \ | |||
26 | return ret; \ | 26 | return ret; \ |
27 | } | 27 | } |
28 | 28 | ||
29 | DEFINE_PRINT_FN(warning, 0) | 29 | DEFINE_PRINT_FN(warning, 1) |
30 | DEFINE_PRINT_FN(info, 0) | 30 | DEFINE_PRINT_FN(info, 1) |
31 | DEFINE_PRINT_FN(debug, 1) | 31 | DEFINE_PRINT_FN(debug, 1) |
32 | 32 | ||
33 | struct bpf_prog_priv { | 33 | struct bpf_prog_priv { |
34 | struct perf_probe_event pev; | 34 | struct perf_probe_event pev; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | static bool libbpf_initialized; | ||
38 | |||
39 | struct bpf_object * | ||
40 | bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name) | ||
41 | { | ||
42 | struct bpf_object *obj; | ||
43 | |||
44 | if (!libbpf_initialized) { | ||
45 | libbpf_set_print(libbpf_warning, | ||
46 | libbpf_info, | ||
47 | libbpf_debug); | ||
48 | libbpf_initialized = true; | ||
49 | } | ||
50 | |||
51 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name); | ||
52 | if (IS_ERR(obj)) { | ||
53 | pr_debug("bpf: failed to load buffer\n"); | ||
54 | return ERR_PTR(-EINVAL); | ||
55 | } | ||
56 | |||
57 | return obj; | ||
58 | } | ||
59 | |||
37 | struct bpf_object *bpf__prepare_load(const char *filename, bool source) | 60 | struct bpf_object *bpf__prepare_load(const char *filename, bool source) |
38 | { | 61 | { |
39 | struct bpf_object *obj; | 62 | struct bpf_object *obj; |
40 | static bool libbpf_initialized; | ||
41 | 63 | ||
42 | if (!libbpf_initialized) { | 64 | if (!libbpf_initialized) { |
43 | libbpf_set_print(libbpf_warning, | 65 | libbpf_set_print(libbpf_warning, |
@@ -53,15 +75,15 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) | |||
53 | 75 | ||
54 | err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); | 76 | err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); |
55 | if (err) | 77 | if (err) |
56 | return ERR_PTR(err); | 78 | return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); |
57 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); | 79 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); |
58 | free(obj_buf); | 80 | free(obj_buf); |
59 | } else | 81 | } else |
60 | obj = bpf_object__open(filename); | 82 | obj = bpf_object__open(filename); |
61 | 83 | ||
62 | if (!obj) { | 84 | if (IS_ERR(obj)) { |
63 | pr_debug("bpf: failed to load %s\n", filename); | 85 | pr_debug("bpf: failed to load %s\n", filename); |
64 | return ERR_PTR(-EINVAL); | 86 | return obj; |
65 | } | 87 | } |
66 | 88 | ||
67 | return obj; | 89 | return obj; |
@@ -96,9 +118,9 @@ config_bpf_program(struct bpf_program *prog) | |||
96 | int err; | 118 | int err; |
97 | 119 | ||
98 | config_str = bpf_program__title(prog, false); | 120 | config_str = bpf_program__title(prog, false); |
99 | if (!config_str) { | 121 | if (IS_ERR(config_str)) { |
100 | pr_debug("bpf: unable to get title for program\n"); | 122 | pr_debug("bpf: unable to get title for program\n"); |
101 | return -EINVAL; | 123 | return PTR_ERR(config_str); |
102 | } | 124 | } |
103 | 125 | ||
104 | priv = calloc(sizeof(*priv), 1); | 126 | priv = calloc(sizeof(*priv), 1); |
@@ -113,14 +135,14 @@ config_bpf_program(struct bpf_program *prog) | |||
113 | if (err < 0) { | 135 | if (err < 0) { |
114 | pr_debug("bpf: '%s' is not a valid config string\n", | 136 | pr_debug("bpf: '%s' is not a valid config string\n", |
115 | config_str); | 137 | config_str); |
116 | err = -EINVAL; | 138 | err = -BPF_LOADER_ERRNO__CONFIG; |
117 | goto errout; | 139 | goto errout; |
118 | } | 140 | } |
119 | 141 | ||
120 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { | 142 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { |
121 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", | 143 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", |
122 | config_str, PERF_BPF_PROBE_GROUP); | 144 | config_str, PERF_BPF_PROBE_GROUP); |
123 | err = -EINVAL; | 145 | err = -BPF_LOADER_ERRNO__GROUP; |
124 | goto errout; | 146 | goto errout; |
125 | } else if (!pev->group) | 147 | } else if (!pev->group) |
126 | pev->group = strdup(PERF_BPF_PROBE_GROUP); | 148 | pev->group = strdup(PERF_BPF_PROBE_GROUP); |
@@ -132,9 +154,9 @@ config_bpf_program(struct bpf_program *prog) | |||
132 | } | 154 | } |
133 | 155 | ||
134 | if (!pev->event) { | 156 | if (!pev->event) { |
135 | pr_debug("bpf: '%s': event name is missing\n", | 157 | pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n", |
136 | config_str); | 158 | config_str); |
137 | err = -EINVAL; | 159 | err = -BPF_LOADER_ERRNO__EVENTNAME; |
138 | goto errout; | 160 | goto errout; |
139 | } | 161 | } |
140 | pr_debug("bpf: config '%s' is ok\n", config_str); | 162 | pr_debug("bpf: config '%s' is ok\n", config_str); |
@@ -285,7 +307,7 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
285 | (void **)&priv); | 307 | (void **)&priv); |
286 | if (err || !priv) { | 308 | if (err || !priv) { |
287 | pr_debug("bpf: failed to get private field\n"); | 309 | pr_debug("bpf: failed to get private field\n"); |
288 | return -EINVAL; | 310 | return -BPF_LOADER_ERRNO__INTERNAL; |
289 | } | 311 | } |
290 | 312 | ||
291 | pev = &priv->pev; | 313 | pev = &priv->pev; |
@@ -308,13 +330,57 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
308 | return 0; | 330 | return 0; |
309 | } | 331 | } |
310 | 332 | ||
333 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | ||
334 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | ||
335 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | ||
336 | |||
337 | static const char *bpf_loader_strerror_table[NR_ERRNO] = { | ||
338 | [ERRCODE_OFFSET(CONFIG)] = "Invalid config string", | ||
339 | [ERRCODE_OFFSET(GROUP)] = "Invalid group name", | ||
340 | [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", | ||
341 | [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", | ||
342 | [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", | ||
343 | }; | ||
344 | |||
345 | static int | ||
346 | bpf_loader_strerror(int err, char *buf, size_t size) | ||
347 | { | ||
348 | char sbuf[STRERR_BUFSIZE]; | ||
349 | const char *msg; | ||
350 | |||
351 | if (!buf || !size) | ||
352 | return -1; | ||
353 | |||
354 | err = err > 0 ? err : -err; | ||
355 | |||
356 | if (err >= __LIBBPF_ERRNO__START) | ||
357 | return libbpf_strerror(err, buf, size); | ||
358 | |||
359 | if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) { | ||
360 | msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)]; | ||
361 | snprintf(buf, size, "%s", msg); | ||
362 | buf[size - 1] = '\0'; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | if (err >= __BPF_LOADER_ERRNO__END) | ||
367 | snprintf(buf, size, "Unknown bpf loader error %d", err); | ||
368 | else | ||
369 | snprintf(buf, size, "%s", | ||
370 | strerror_r(err, sbuf, sizeof(sbuf))); | ||
371 | |||
372 | buf[size - 1] = '\0'; | ||
373 | return -1; | ||
374 | } | ||
375 | |||
311 | #define bpf__strerror_head(err, buf, size) \ | 376 | #define bpf__strerror_head(err, buf, size) \ |
312 | char sbuf[STRERR_BUFSIZE], *emsg;\ | 377 | char sbuf[STRERR_BUFSIZE], *emsg;\ |
313 | if (!size)\ | 378 | if (!size)\ |
314 | return 0;\ | 379 | return 0;\ |
315 | if (err < 0)\ | 380 | if (err < 0)\ |
316 | err = -err;\ | 381 | err = -err;\ |
317 | emsg = strerror_r(err, sbuf, sizeof(sbuf));\ | 382 | bpf_loader_strerror(err, sbuf, sizeof(sbuf));\ |
383 | emsg = sbuf;\ | ||
318 | switch (err) {\ | 384 | switch (err) {\ |
319 | default:\ | 385 | default:\ |
320 | scnprintf(buf, size, "%s", emsg);\ | 386 | scnprintf(buf, size, "%s", emsg);\ |
@@ -330,23 +396,62 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
330 | }\ | 396 | }\ |
331 | buf[size - 1] = '\0'; | 397 | buf[size - 1] = '\0'; |
332 | 398 | ||
399 | int bpf__strerror_prepare_load(const char *filename, bool source, | ||
400 | int err, char *buf, size_t size) | ||
401 | { | ||
402 | size_t n; | ||
403 | int ret; | ||
404 | |||
405 | n = snprintf(buf, size, "Failed to load %s%s: ", | ||
406 | filename, source ? " from source" : ""); | ||
407 | if (n >= size) { | ||
408 | buf[size - 1] = '\0'; | ||
409 | return 0; | ||
410 | } | ||
411 | buf += n; | ||
412 | size -= n; | ||
413 | |||
414 | ret = bpf_loader_strerror(err, buf, size); | ||
415 | buf[size - 1] = '\0'; | ||
416 | return ret; | ||
417 | } | ||
418 | |||
333 | int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | 419 | int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, |
334 | int err, char *buf, size_t size) | 420 | int err, char *buf, size_t size) |
335 | { | 421 | { |
336 | bpf__strerror_head(err, buf, size); | 422 | bpf__strerror_head(err, buf, size); |
337 | bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); | 423 | bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); |
338 | bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); | 424 | bpf__strerror_entry(EACCES, "You need to be root"); |
339 | bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); | 425 | bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0"); |
426 | bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file"); | ||
340 | bpf__strerror_end(buf, size); | 427 | bpf__strerror_end(buf, size); |
341 | return 0; | 428 | return 0; |
342 | } | 429 | } |
343 | 430 | ||
344 | int bpf__strerror_load(struct bpf_object *obj __maybe_unused, | 431 | int bpf__strerror_load(struct bpf_object *obj, |
345 | int err, char *buf, size_t size) | 432 | int err, char *buf, size_t size) |
346 | { | 433 | { |
347 | bpf__strerror_head(err, buf, size); | 434 | bpf__strerror_head(err, buf, size); |
348 | bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", | 435 | case LIBBPF_ERRNO__KVER: { |
349 | emsg) | 436 | unsigned int obj_kver = bpf_object__get_kversion(obj); |
437 | unsigned int real_kver; | ||
438 | |||
439 | if (fetch_kernel_version(&real_kver, NULL, 0)) { | ||
440 | scnprintf(buf, size, "Unable to fetch kernel version"); | ||
441 | break; | ||
442 | } | ||
443 | |||
444 | if (obj_kver != real_kver) { | ||
445 | scnprintf(buf, size, | ||
446 | "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")", | ||
447 | KVER_PARAM(obj_kver), | ||
448 | KVER_PARAM(real_kver)); | ||
449 | break; | ||
450 | } | ||
451 | |||
452 | scnprintf(buf, size, "Failed to load program for unknown reason"); | ||
453 | break; | ||
454 | } | ||
350 | bpf__strerror_end(buf, size); | 455 | bpf__strerror_end(buf, size); |
351 | return 0; | 456 | return 0; |
352 | } | 457 | } |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index ccd8d7fd79d3..9caf3ae4acf3 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
@@ -8,9 +8,21 @@ | |||
8 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <string.h> | 10 | #include <string.h> |
11 | #include <bpf/libbpf.h> | ||
11 | #include "probe-event.h" | 12 | #include "probe-event.h" |
12 | #include "debug.h" | 13 | #include "debug.h" |
13 | 14 | ||
15 | enum bpf_loader_errno { | ||
16 | __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100, | ||
17 | /* Invalid config string */ | ||
18 | BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START, | ||
19 | BPF_LOADER_ERRNO__GROUP, /* Invalid group name */ | ||
20 | BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ | ||
21 | BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ | ||
22 | BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ | ||
23 | __BPF_LOADER_ERRNO__END, | ||
24 | }; | ||
25 | |||
14 | struct bpf_object; | 26 | struct bpf_object; |
15 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" | 27 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" |
16 | 28 | ||
@@ -19,6 +31,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, | |||
19 | 31 | ||
20 | #ifdef HAVE_LIBBPF_SUPPORT | 32 | #ifdef HAVE_LIBBPF_SUPPORT |
21 | struct bpf_object *bpf__prepare_load(const char *filename, bool source); | 33 | struct bpf_object *bpf__prepare_load(const char *filename, bool source); |
34 | int bpf__strerror_prepare_load(const char *filename, bool source, | ||
35 | int err, char *buf, size_t size); | ||
36 | |||
37 | struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, | ||
38 | const char *name); | ||
22 | 39 | ||
23 | void bpf__clear(void); | 40 | void bpf__clear(void); |
24 | 41 | ||
@@ -41,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused, | |||
41 | return ERR_PTR(-ENOTSUP); | 58 | return ERR_PTR(-ENOTSUP); |
42 | } | 59 | } |
43 | 60 | ||
61 | static inline struct bpf_object * | ||
62 | bpf__prepare_load_buffer(void *obj_buf __maybe_unused, | ||
63 | size_t obj_buf_sz __maybe_unused) | ||
64 | { | ||
65 | return ERR_PTR(-ENOTSUP); | ||
66 | } | ||
67 | |||
44 | static inline void bpf__clear(void) { } | 68 | static inline void bpf__clear(void) { } |
45 | 69 | ||
46 | static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} | 70 | static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} |
@@ -67,6 +91,15 @@ __bpf_strerror(char *buf, size_t size) | |||
67 | return 0; | 91 | return 0; |
68 | } | 92 | } |
69 | 93 | ||
94 | static inline | ||
95 | int bpf__strerror_prepare_load(const char *filename __maybe_unused, | ||
96 | bool source __maybe_unused, | ||
97 | int err __maybe_unused, | ||
98 | char *buf, size_t size) | ||
99 | { | ||
100 | return __bpf_strerror(buf, size); | ||
101 | } | ||
102 | |||
70 | static inline int | 103 | static inline int |
71 | bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | 104 | bpf__strerror_probe(struct bpf_object *obj __maybe_unused, |
72 | int err __maybe_unused, | 105 | int err __maybe_unused, |
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 4f6a4780bd5f..00724d496d38 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c | |||
@@ -4,17 +4,18 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <sys/utsname.h> | ||
8 | #include "util.h" | 7 | #include "util.h" |
9 | #include "debug.h" | 8 | #include "debug.h" |
10 | #include "llvm-utils.h" | 9 | #include "llvm-utils.h" |
11 | #include "cache.h" | 10 | #include "cache.h" |
12 | 11 | ||
13 | #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ | 12 | #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ |
14 | "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \ | 13 | "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ |
15 | "$KERNEL_INC_OPTIONS -Wno-unused-value " \ | 14 | "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ |
16 | "-Wno-pointer-sign -working-directory " \ | 15 | "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \ |
17 | "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -" | 16 | "-Wno-unused-value -Wno-pointer-sign " \ |
17 | "-working-directory $WORKING_DIR " \ | ||
18 | "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -" | ||
18 | 19 | ||
19 | struct llvm_param llvm_param = { | 20 | struct llvm_param llvm_param = { |
20 | .clang_path = "clang", | 21 | .clang_path = "clang", |
@@ -214,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir) | |||
214 | const char *suffix_dir = ""; | 215 | const char *suffix_dir = ""; |
215 | 216 | ||
216 | char *autoconf_path; | 217 | char *autoconf_path; |
217 | struct utsname utsname; | ||
218 | 218 | ||
219 | int err; | 219 | int err; |
220 | 220 | ||
221 | if (!test_dir) { | 221 | if (!test_dir) { |
222 | err = uname(&utsname); | 222 | /* _UTSNAME_LENGTH is 65 */ |
223 | if (err) { | 223 | char release[128]; |
224 | pr_warning("uname failed: %s\n", strerror(errno)); | 224 | |
225 | err = fetch_kernel_version(NULL, release, | ||
226 | sizeof(release)); | ||
227 | if (err) | ||
225 | return -EINVAL; | 228 | return -EINVAL; |
226 | } | ||
227 | 229 | ||
228 | test_dir = utsname.release; | 230 | test_dir = release; |
229 | prefix_dir = "/lib/modules/"; | 231 | prefix_dir = "/lib/modules/"; |
230 | suffix_dir = "/build"; | 232 | suffix_dir = "/build"; |
231 | } | 233 | } |
@@ -326,13 +328,15 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts) | |||
326 | int llvm__compile_bpf(const char *path, void **p_obj_buf, | 328 | int llvm__compile_bpf(const char *path, void **p_obj_buf, |
327 | size_t *p_obj_buf_sz) | 329 | size_t *p_obj_buf_sz) |
328 | { | 330 | { |
329 | int err; | 331 | size_t obj_buf_sz; |
330 | char clang_path[PATH_MAX]; | 332 | void *obj_buf = NULL; |
333 | int err, nr_cpus_avail; | ||
334 | unsigned int kernel_version; | ||
335 | char linux_version_code_str[64]; | ||
331 | const char *clang_opt = llvm_param.clang_opt; | 336 | const char *clang_opt = llvm_param.clang_opt; |
332 | const char *template = llvm_param.clang_bpf_cmd_template; | 337 | char clang_path[PATH_MAX], nr_cpus_avail_str[64]; |
333 | char *kbuild_dir = NULL, *kbuild_include_opts = NULL; | 338 | char *kbuild_dir = NULL, *kbuild_include_opts = NULL; |
334 | void *obj_buf = NULL; | 339 | const char *template = llvm_param.clang_bpf_cmd_template; |
335 | size_t obj_buf_sz; | ||
336 | 340 | ||
337 | if (!template) | 341 | if (!template) |
338 | template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; | 342 | template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; |
@@ -354,6 +358,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, | |||
354 | */ | 358 | */ |
355 | get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); | 359 | get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); |
356 | 360 | ||
361 | nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF); | ||
362 | if (nr_cpus_avail <= 0) { | ||
363 | pr_err( | ||
364 | "WARNING:\tunable to get available CPUs in this system: %s\n" | ||
365 | " \tUse 128 instead.\n", strerror(errno)); | ||
366 | nr_cpus_avail = 128; | ||
367 | } | ||
368 | snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d", | ||
369 | nr_cpus_avail); | ||
370 | |||
371 | if (fetch_kernel_version(&kernel_version, NULL, 0)) | ||
372 | kernel_version = 0; | ||
373 | |||
374 | snprintf(linux_version_code_str, sizeof(linux_version_code_str), | ||
375 | "0x%x", kernel_version); | ||
376 | |||
377 | force_set_env("NR_CPUS", nr_cpus_avail_str); | ||
378 | force_set_env("LINUX_VERSION_CODE", linux_version_code_str); | ||
357 | force_set_env("CLANG_EXEC", clang_path); | 379 | force_set_env("CLANG_EXEC", clang_path); |
358 | force_set_env("CLANG_OPTIONS", clang_opt); | 380 | force_set_env("CLANG_OPTIONS", clang_opt); |
359 | force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); | 381 | force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 4e38c396a897..afc6b56cf749 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) | |||
644 | return printed; | 644 | return printed; |
645 | } | 645 | } |
646 | 646 | ||
647 | static void __map_groups__insert(struct map_groups *mg, struct map *map) | ||
648 | { | ||
649 | __maps__insert(&mg->maps[map->type], map); | ||
650 | map->groups = mg; | ||
651 | } | ||
652 | |||
647 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) | 653 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) |
648 | { | 654 | { |
649 | struct rb_root *root; | 655 | struct rb_root *root; |
@@ -682,7 +688,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp | |||
682 | } | 688 | } |
683 | 689 | ||
684 | before->end = map->start; | 690 | before->end = map->start; |
685 | __maps__insert(maps, before); | 691 | __map_groups__insert(pos->groups, before); |
686 | if (verbose >= 2) | 692 | if (verbose >= 2) |
687 | map__fprintf(before, fp); | 693 | map__fprintf(before, fp); |
688 | } | 694 | } |
@@ -696,7 +702,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp | |||
696 | } | 702 | } |
697 | 703 | ||
698 | after->start = map->end; | 704 | after->start = map->end; |
699 | __maps__insert(maps, after); | 705 | __map_groups__insert(pos->groups, after); |
700 | if (verbose >= 2) | 706 | if (verbose >= 2) |
701 | map__fprintf(after, fp); | 707 | map__fprintf(after, fp); |
702 | } | 708 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bee60583839a..e48d9da75707 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -632,19 +632,20 @@ int parse_events_load_bpf(struct parse_events_evlist *data, | |||
632 | struct bpf_object *obj; | 632 | struct bpf_object *obj; |
633 | 633 | ||
634 | obj = bpf__prepare_load(bpf_file_name, source); | 634 | obj = bpf__prepare_load(bpf_file_name, source); |
635 | if (IS_ERR(obj) || !obj) { | 635 | if (IS_ERR(obj)) { |
636 | char errbuf[BUFSIZ]; | 636 | char errbuf[BUFSIZ]; |
637 | int err; | 637 | int err; |
638 | 638 | ||
639 | err = obj ? PTR_ERR(obj) : -EINVAL; | 639 | err = PTR_ERR(obj); |
640 | 640 | ||
641 | if (err == -ENOTSUP) | 641 | if (err == -ENOTSUP) |
642 | snprintf(errbuf, sizeof(errbuf), | 642 | snprintf(errbuf, sizeof(errbuf), |
643 | "BPF support is not compiled"); | 643 | "BPF support is not compiled"); |
644 | else | 644 | else |
645 | snprintf(errbuf, sizeof(errbuf), | 645 | bpf__strerror_prepare_load(bpf_file_name, |
646 | "BPF object file '%s' is invalid", | 646 | source, |
647 | bpf_file_name); | 647 | -err, errbuf, |
648 | sizeof(errbuf)); | ||
648 | 649 | ||
649 | data->error->help = strdup("(add -v to see detail)"); | 650 | data->error->help = strdup("(add -v to see detail)"); |
650 | data->error->str = strdup(errbuf); | 651 | data->error->str = strdup(errbuf); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b51a8bfb40f9..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, | |||
1895 | sym = map__find_symbol(map, addr, NULL); | 1895 | sym = map__find_symbol(map, addr, NULL); |
1896 | } else { | 1896 | } else { |
1897 | if (tp->symbol && !addr) { | 1897 | if (tp->symbol && !addr) { |
1898 | ret = kernel_get_symbol_address_by_name(tp->symbol, | 1898 | if (kernel_get_symbol_address_by_name(tp->symbol, |
1899 | &addr, true, false); | 1899 | &addr, true, false) < 0) |
1900 | if (ret < 0) | ||
1901 | goto out; | 1900 | goto out; |
1902 | } | 1901 | } |
1903 | if (addr) { | 1902 | if (addr) { |
@@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | |||
1905 | sym = __find_kernel_function(addr, &map); | 1904 | sym = __find_kernel_function(addr, &map); |
1906 | } | 1905 | } |
1907 | } | 1906 | } |
1907 | |||
1908 | if (!sym) | 1908 | if (!sym) |
1909 | goto out; | 1909 | goto out; |
1910 | 1910 | ||
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 89dbeb92c68e..e3b3b92e4458 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd) | |||
138 | char *p; | 138 | char *p; |
139 | struct strlist *sl; | 139 | struct strlist *sl; |
140 | 140 | ||
141 | if (fd < 0) | ||
142 | return NULL; | ||
143 | |||
141 | sl = strlist__new(NULL, NULL); | 144 | sl = strlist__new(NULL, NULL); |
142 | 145 | ||
143 | fp = fdopen(dup(fd), "r"); | 146 | fp = fdopen(dup(fd), "r"); |
@@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, | |||
271 | const char *p; | 274 | const char *p; |
272 | int ret = -ENOENT; | 275 | int ret = -ENOENT; |
273 | 276 | ||
277 | if (!plist) | ||
278 | return -EINVAL; | ||
279 | |||
274 | namelist = __probe_file__get_namelist(fd, true); | 280 | namelist = __probe_file__get_namelist(fd, true); |
275 | if (!namelist) | 281 | if (!namelist) |
276 | return -ENOENT; | 282 | return -ENOENT; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 428149bc64d2..c35ffdd360fe 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -29,7 +29,7 @@ static int perf_session__open(struct perf_session *session) | |||
29 | struct perf_data_file *file = session->file; | 29 | struct perf_data_file *file = session->file; |
30 | 30 | ||
31 | if (perf_session__read_header(session) < 0) { | 31 | if (perf_session__read_header(session) < 0) { |
32 | pr_err("incompatible file format (rerun with -v to learn more)"); | 32 | pr_err("incompatible file format (rerun with -v to learn more)\n"); |
33 | return -1; | 33 | return -1; |
34 | } | 34 | } |
35 | 35 | ||
@@ -37,17 +37,17 @@ static int perf_session__open(struct perf_session *session) | |||
37 | return 0; | 37 | return 0; |
38 | 38 | ||
39 | if (!perf_evlist__valid_sample_type(session->evlist)) { | 39 | if (!perf_evlist__valid_sample_type(session->evlist)) { |
40 | pr_err("non matching sample_type"); | 40 | pr_err("non matching sample_type\n"); |
41 | return -1; | 41 | return -1; |
42 | } | 42 | } |
43 | 43 | ||
44 | if (!perf_evlist__valid_sample_id_all(session->evlist)) { | 44 | if (!perf_evlist__valid_sample_id_all(session->evlist)) { |
45 | pr_err("non matching sample_id_all"); | 45 | pr_err("non matching sample_id_all\n"); |
46 | return -1; | 46 | return -1; |
47 | } | 47 | } |
48 | 48 | ||
49 | if (!perf_evlist__valid_read_format(session->evlist)) { | 49 | if (!perf_evlist__valid_read_format(session->evlist)) { |
50 | pr_err("non matching read_format"); | 50 | pr_err("non matching read_format\n"); |
51 | return -1; | 51 | return -1; |
52 | } | 52 | } |
53 | 53 | ||
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 2a5d8d7698ae..6ac03146889d 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c | |||
@@ -413,6 +413,11 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, | |||
413 | ratio = total / avg; | 413 | ratio = total / avg; |
414 | 414 | ||
415 | fprintf(out, " # %8.0f cycles / elision ", ratio); | 415 | fprintf(out, " # %8.0f cycles / elision ", ratio); |
416 | } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) { | ||
417 | if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) | ||
418 | fprintf(out, " # %8.3f CPUs utilized ", avg / ratio); | ||
419 | else | ||
420 | fprintf(out, " "); | ||
416 | } else if (runtime_nsecs_stats[cpu].n != 0) { | 421 | } else if (runtime_nsecs_stats[cpu].n != 0) { |
417 | char unit = 'M'; | 422 | char unit = 'M'; |
418 | 423 | ||
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 @@ | |||
3 | #include "debug.h" | 3 | #include "debug.h" |
4 | #include <api/fs/fs.h> | 4 | #include <api/fs/fs.h> |
5 | #include <sys/mman.h> | 5 | #include <sys/mman.h> |
6 | #include <sys/utsname.h> | ||
6 | #ifdef HAVE_BACKTRACE_SUPPORT | 7 | #ifdef HAVE_BACKTRACE_SUPPORT |
7 | #include <execinfo.h> | 8 | #include <execinfo.h> |
8 | #endif | 9 | #endif |
@@ -665,3 +666,32 @@ bool find_process(const char *name) | |||
665 | closedir(dir); | 666 | closedir(dir); |
666 | return ret ? false : true; | 667 | return ret ? false : true; |
667 | } | 668 | } |
669 | |||
670 | int | ||
671 | fetch_kernel_version(unsigned int *puint, char *str, | ||
672 | size_t str_size) | ||
673 | { | ||
674 | struct utsname utsname; | ||
675 | int version, patchlevel, sublevel, err; | ||
676 | |||
677 | if (uname(&utsname)) | ||
678 | return -1; | ||
679 | |||
680 | if (str && str_size) { | ||
681 | strncpy(str, utsname.release, str_size); | ||
682 | str[str_size - 1] = '\0'; | ||
683 | } | ||
684 | |||
685 | err = sscanf(utsname.release, "%d.%d.%d", | ||
686 | &version, &patchlevel, &sublevel); | ||
687 | |||
688 | if (err != 3) { | ||
689 | pr_debug("Unablt to get kernel version from uname '%s'\n", | ||
690 | utsname.release); | ||
691 | return -1; | ||
692 | } | ||
693 | |||
694 | if (puint) | ||
695 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
696 | return 0; | ||
697 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 4cfb913aa9e0..dcc659017976 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -350,4 +350,12 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int | |||
350 | 350 | ||
351 | int get_stack_size(const char *str, unsigned long *_size); | 351 | int get_stack_size(const char *str, unsigned long *_size); |
352 | 352 | ||
353 | int fetch_kernel_version(unsigned int *puint, | ||
354 | char *str, size_t str_sz); | ||
355 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) | ||
356 | #define KVER_PATCHLEVEL(x) (((x) >> 8) & 0xff) | ||
357 | #define KVER_SUBLEVEL(x) ((x) & 0xff) | ||
358 | #define KVER_FMT "%d.%d.%d" | ||
359 | #define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) | ||
360 | |||
353 | #endif /* GIT_COMPAT_UTIL_H */ | 361 | #endif /* GIT_COMPAT_UTIL_H */ |