aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-12-20 14:13:37 -0500
committerIngo Molnar <mingo@kernel.org>2016-12-20 14:13:37 -0500
commit037569172083a59c0cc5b66c5e1cf80dcf27ebb7 (patch)
treede00115c5bbf4b55f8f5ac5e6e990e2aacf7a044 /tools/perf
parent297e765e390a2ac996000b5f7228cbd84d995174 (diff)
parent9899694a7f67714216665b87318eb367e2c5c901 (diff)
Merge tag 'perf-core-for-mingo-20161220' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes: New features: - Introduce 'perf sched timehist --idle', to analyse processes going to/from idle state (Namhyung Kim) Fixes: - Allow 'perf record -u user' to continue when facing races with threads going away after having scanned them via /proc (Jiri Olsa) - Fix 'perf mem' --all-user/--all-kernel options (Jiri Olsa) - Support jumps with multiple arguments (Ravi Bangoria) - Fix jumps to before the function where they are located (Ravi Bangoria) - Fix lock-pi help string (Davidlohr Bueso) - Fix build of 'perf trace' in odd systems such as a RHEL PPC one (Jiri Olsa) - Do not overwrite valid build id in 'perf diff' (Kan Liang) - Don't throw error for zero length symbols, allowing the use of the TUI in PowerPC, where such symbols became more common recently (Ravi Bangoria) Infrastructure changes: - Switch of samples/bpf/ to use tools/lib/bpf, removing libbpf duplication (Joe Stringer) - Move headers check into bash script (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-sched.txt4
-rw-r--r--tools/perf/Makefile.perf94
-rw-r--r--tools/perf/bench/futex-lock-pi.c2
-rw-r--r--tools/perf/builtin-c2c.c13
-rw-r--r--tools/perf/builtin-mem.c4
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-sched.c261
-rw-r--r--tools/perf/builtin-stat.c6
-rwxr-xr-xtools/perf/check-headers.sh59
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/tests/thread-map.c44
-rw-r--r--tools/perf/trace/beauty/mmap.c2
-rw-r--r--tools/perf/ui/browsers/annotate.c5
-rw-r--r--tools/perf/util/annotate.c23
-rw-r--r--tools/perf/util/annotate.h5
-rw-r--r--tools/perf/util/evsel.c61
-rw-r--r--tools/perf/util/evsel.h1
-rw-r--r--tools/perf/util/symbol.c3
-rw-r--r--tools/perf/util/thread_map.c22
-rw-r--r--tools/perf/util/thread_map.h1
23 files changed, 460 insertions, 161 deletions
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 7775b1eb2bee..76173969ab80 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -132,6 +132,10 @@ OPTIONS for 'perf sched timehist'
132--migrations:: 132--migrations::
133 Show migration events. 133 Show migration events.
134 134
135-I::
136--idle-hist::
137 Show idle-related events only.
138
135--time:: 139--time::
136 Only analyze samples within given time window: <start>,<stop>. Times 140 Only analyze samples within given time window: <start>,<stop>. Times
137 have the format seconds.microseconds. If start is not given (i.e., time 141 have the format seconds.microseconds. If start is not given (i.e., time
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 8f1c258b151a..e9ec531131ca 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -201,6 +201,7 @@ goals := $(filter-out all sub-make, $(MAKECMDGOALS))
201$(goals) all: sub-make 201$(goals) all: sub-make
202 202
203sub-make: fixdep 203sub-make: fixdep
204 @./check-headers.sh
204 $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals) 205 $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals)
205 206
206else # force_fixdep 207else # force_fixdep
@@ -404,99 +405,6 @@ export JEVENTS
404build := -f $(srctree)/tools/build/Makefile.build dir=. obj 405build := -f $(srctree)/tools/build/Makefile.build dir=. obj
405 406
406$(PERF_IN): prepare FORCE 407$(PERF_IN): prepare FORCE
407 @(test -f ../../include/uapi/linux/perf_event.h && ( \
408 (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \
409 || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true
410 @(test -f ../../include/linux/hash.h && ( \
411 (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \
412 || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true
413 @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \
414 (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \
415 || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true
416 @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \
417 (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \
418 || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true
419 @(test -f ../../arch/x86/include/asm/required-features.h && ( \
420 (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \
421 || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true
422 @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \
423 (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \
424 || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true
425 @(test -f ../../arch/x86/lib/memcpy_64.S && ( \
426 (diff -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \
427 || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true
428 @(test -f ../../arch/x86/lib/memset_64.S && ( \
429 (diff -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \
430 || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true
431 @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \
432 (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \
433 || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
434 @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \
435 (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \
436 || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
437 @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \
438 (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \
439 || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
440 @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \
441 (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \
442 || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
443 @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \
444 (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \
445 || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
446 @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \
447 (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \
448 || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true
449 @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \
450 (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \
451 || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true
452 @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \
453 (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \
454 || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true
455 @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \
456 (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \
457 || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
458 @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \
459 (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \
460 || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
461 @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \
462 (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \
463 || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true
464 @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \
465 (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \
466 || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true
467 @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \
468 (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \
469 || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
470 @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \
471 (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \
472 || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
473 @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \
474 (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \
475 || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true
476 @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \
477 (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \
478 || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true
479 @(test -f ../../include/asm-generic/bitops/__fls.h && ( \
480 (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \
481 || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true
482 @(test -f ../../include/asm-generic/bitops/fls.h && ( \
483 (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \
484 || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true
485 @(test -f ../../include/asm-generic/bitops/fls64.h && ( \
486 (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \
487 || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true
488 @(test -f ../../include/linux/coresight-pmu.h && ( \
489 (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \
490 || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true
491 @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \
492 (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \
493 || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true
494 @(test -f ../../include/uapi/asm-generic/mman.h && ( \
495 (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \
496 || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true
497 @(test -f ../../include/uapi/linux/mman.h && ( \
498 (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \
499 || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
500 $(Q)$(MAKE) $(build)=perf 408 $(Q)$(MAKE) $(build)=perf
501 409
502$(JEVENTS_IN): FORCE 410$(JEVENTS_IN): FORCE
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index 465012b320ee..6d9d6c40a916 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -48,7 +48,7 @@ static const struct option options[] = {
48}; 48};
49 49
50static const char * const bench_futex_lock_pi_usage[] = { 50static const char * const bench_futex_lock_pi_usage[] = {
51 "perf bench futex requeue <options>", 51 "perf bench futex lock-pi <options>",
52 NULL 52 NULL
53}; 53};
54 54
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 4b419631753d..f8ca7a4ebabc 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -208,7 +208,7 @@ static void compute_stats(struct c2c_hist_entry *c2c_he,
208static int process_sample_event(struct perf_tool *tool __maybe_unused, 208static int process_sample_event(struct perf_tool *tool __maybe_unused,
209 union perf_event *event, 209 union perf_event *event,
210 struct perf_sample *sample, 210 struct perf_sample *sample,
211 struct perf_evsel *evsel __maybe_unused, 211 struct perf_evsel *evsel,
212 struct machine *machine) 212 struct machine *machine)
213{ 213{
214 struct c2c_hists *c2c_hists = &c2c.hists; 214 struct c2c_hists *c2c_hists = &c2c.hists;
@@ -379,7 +379,7 @@ static int symbol_width(struct hists *hists, struct sort_entry *se)
379 379
380static int c2c_width(struct perf_hpp_fmt *fmt, 380static int c2c_width(struct perf_hpp_fmt *fmt,
381 struct perf_hpp *hpp __maybe_unused, 381 struct perf_hpp *hpp __maybe_unused,
382 struct hists *hists __maybe_unused) 382 struct hists *hists)
383{ 383{
384 struct c2c_fmt *c2c_fmt; 384 struct c2c_fmt *c2c_fmt;
385 struct c2c_dimension *dim; 385 struct c2c_dimension *dim;
@@ -1127,7 +1127,7 @@ MEAN_ENTRY(mean_lcl_entry, lcl_hitm);
1127MEAN_ENTRY(mean_load_entry, load); 1127MEAN_ENTRY(mean_load_entry, load);
1128 1128
1129static int 1129static int
1130cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, 1130cpucnt_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1131 struct hist_entry *he) 1131 struct hist_entry *he)
1132{ 1132{
1133 struct c2c_hist_entry *c2c_he; 1133 struct c2c_hist_entry *c2c_he;
@@ -1141,7 +1141,7 @@ cpucnt_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1141} 1141}
1142 1142
1143static int 1143static int
1144cl_idx_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, 1144cl_idx_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1145 struct hist_entry *he) 1145 struct hist_entry *he)
1146{ 1146{
1147 struct c2c_hist_entry *c2c_he; 1147 struct c2c_hist_entry *c2c_he;
@@ -1155,7 +1155,7 @@ cl_idx_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
1155} 1155}
1156 1156
1157static int 1157static int
1158cl_idx_empty_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, 1158cl_idx_empty_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1159 struct hist_entry *he) 1159 struct hist_entry *he)
1160{ 1160{
1161 int width = c2c_width(fmt, hpp, he->hists); 1161 int width = c2c_width(fmt, hpp, he->hists);
@@ -1779,7 +1779,6 @@ static int c2c_hists__init(struct c2c_hists *hists,
1779 return hpp_list__parse(&hists->list, NULL, sort); 1779 return hpp_list__parse(&hists->list, NULL, sort);
1780} 1780}
1781 1781
1782__maybe_unused
1783static int c2c_hists__reinit(struct c2c_hists *c2c_hists, 1782static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
1784 const char *output, 1783 const char *output,
1785 const char *sort) 1784 const char *sort)
@@ -2658,7 +2657,7 @@ out:
2658 return err; 2657 return err;
2659} 2658}
2660 2659
2661static int parse_record_events(const struct option *opt __maybe_unused, 2660static int parse_record_events(const struct option *opt,
2662 const char *str, int unset __maybe_unused) 2661 const char *str, int unset __maybe_unused)
2663{ 2662{
2664 bool *event_set = (bool *) opt->value; 2663 bool *event_set = (bool *) opt->value;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index d1ce29be560e..cd7bc4d104e2 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -70,8 +70,8 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
70 OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), 70 OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"),
71 OPT_INCR('v', "verbose", &verbose, 71 OPT_INCR('v', "verbose", &verbose,
72 "be more verbose (show counter open errors, etc)"), 72 "be more verbose (show counter open errors, etc)"),
73 OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), 73 OPT_BOOLEAN('U', "all-user", &all_user, "collect only user level data"),
74 OPT_BOOLEAN('K', "--all-kernel", &all_kernel, "collect only kernel level data"), 74 OPT_BOOLEAN('K', "all-kernel", &all_kernel, "collect only kernel level data"),
75 OPT_END() 75 OPT_END()
76 }; 76 };
77 77
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index fa26865364b6..74d6a035133a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1687,6 +1687,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1687 goto out; 1687 goto out;
1688 } 1688 }
1689 1689
1690 /* Enable ignoring missing threads when -u option is defined. */
1691 rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX;
1692
1690 err = -ENOMEM; 1693 err = -ENOMEM;
1691 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) 1694 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1692 usage_with_options(record_usage, record_options); 1695 usage_with_options(record_usage, record_options);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d2afbe4a240d..06cc759a4597 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -648,7 +648,7 @@ report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
648} 648}
649 649
650static int 650static int
651parse_branch_mode(const struct option *opt __maybe_unused, 651parse_branch_mode(const struct option *opt,
652 const char *str __maybe_unused, int unset) 652 const char *str __maybe_unused, int unset)
653{ 653{
654 int *branch_mode = opt->value; 654 int *branch_mode = opt->value;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 1a3f1be93372..c1c07bfe132c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -200,6 +200,7 @@ struct perf_sched {
200 /* options for timehist command */ 200 /* options for timehist command */
201 bool summary; 201 bool summary;
202 bool summary_only; 202 bool summary_only;
203 bool idle_hist;
203 bool show_callchain; 204 bool show_callchain;
204 unsigned int max_stack; 205 unsigned int max_stack;
205 bool show_cpu_visual; 206 bool show_cpu_visual;
@@ -230,6 +231,15 @@ struct evsel_runtime {
230 u32 ncpu; /* highest cpu slot allocated */ 231 u32 ncpu; /* highest cpu slot allocated */
231}; 232};
232 233
234/* per cpu idle time data */
235struct idle_thread_runtime {
236 struct thread_runtime tr;
237 struct thread *last_thread;
238 struct rb_root sorted_root;
239 struct callchain_root callchain;
240 struct callchain_cursor cursor;
241};
242
233/* track idle times per cpu */ 243/* track idle times per cpu */
234static struct thread **idle_threads; 244static struct thread **idle_threads;
235static int idle_max_cpu; 245static int idle_max_cpu;
@@ -1939,39 +1949,40 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
1939 r->total_run_time += r->dt_run; 1949 r->total_run_time += r->dt_run;
1940} 1950}
1941 1951
1942static bool is_idle_sample(struct perf_sched *sched, 1952static bool is_idle_sample(struct perf_sample *sample,
1943 struct perf_sample *sample, 1953 struct perf_evsel *evsel)
1944 struct perf_evsel *evsel,
1945 struct machine *machine)
1946{ 1954{
1947 struct thread *thread;
1948 struct callchain_cursor *cursor = &callchain_cursor;
1949
1950 /* pid 0 == swapper == idle task */ 1955 /* pid 0 == swapper == idle task */
1951 if (sample->pid == 0) 1956 if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0)
1952 return true; 1957 return perf_evsel__intval(evsel, sample, "prev_pid") == 0;
1953 1958
1954 if (strcmp(perf_evsel__name(evsel), "sched:sched_switch") == 0) { 1959 return sample->pid == 0;
1955 if (perf_evsel__intval(evsel, sample, "prev_pid") == 0) 1960}
1956 return true; 1961
1957 } 1962static void save_task_callchain(struct perf_sched *sched,
1963 struct perf_sample *sample,
1964 struct perf_evsel *evsel,
1965 struct machine *machine)
1966{
1967 struct callchain_cursor *cursor = &callchain_cursor;
1968 struct thread *thread;
1958 1969
1959 /* want main thread for process - has maps */ 1970 /* want main thread for process - has maps */
1960 thread = machine__findnew_thread(machine, sample->pid, sample->pid); 1971 thread = machine__findnew_thread(machine, sample->pid, sample->pid);
1961 if (thread == NULL) { 1972 if (thread == NULL) {
1962 pr_debug("Failed to get thread for pid %d.\n", sample->pid); 1973 pr_debug("Failed to get thread for pid %d.\n", sample->pid);
1963 return false; 1974 return;
1964 } 1975 }
1965 1976
1966 if (!symbol_conf.use_callchain || sample->callchain == NULL) 1977 if (!symbol_conf.use_callchain || sample->callchain == NULL)
1967 return false; 1978 return;
1968 1979
1969 if (thread__resolve_callchain(thread, cursor, evsel, sample, 1980 if (thread__resolve_callchain(thread, cursor, evsel, sample,
1970 NULL, NULL, sched->max_stack + 2) != 0) { 1981 NULL, NULL, sched->max_stack + 2) != 0) {
1971 if (verbose) 1982 if (verbose)
1972 error("Failed to resolve callchain. Skipping\n"); 1983 error("Failed to resolve callchain. Skipping\n");
1973 1984
1974 return false; 1985 return;
1975 } 1986 }
1976 1987
1977 callchain_cursor_commit(cursor); 1988 callchain_cursor_commit(cursor);
@@ -1994,8 +2005,24 @@ static bool is_idle_sample(struct perf_sched *sched,
1994 2005
1995 callchain_cursor_advance(cursor); 2006 callchain_cursor_advance(cursor);
1996 } 2007 }
2008}
2009
2010static int init_idle_thread(struct thread *thread)
2011{
2012 struct idle_thread_runtime *itr;
2013
2014 thread__set_comm(thread, idle_comm, 0);
2015
2016 itr = zalloc(sizeof(*itr));
2017 if (itr == NULL)
2018 return -ENOMEM;
2019
2020 init_stats(&itr->tr.run_stats);
2021 callchain_init(&itr->callchain);
2022 callchain_cursor_reset(&itr->cursor);
2023 thread__set_priv(thread, itr);
1997 2024
1998 return false; 2025 return 0;
1999} 2026}
2000 2027
2001/* 2028/*
@@ -2004,7 +2031,7 @@ static bool is_idle_sample(struct perf_sched *sched,
2004 */ 2031 */
2005static int init_idle_threads(int ncpu) 2032static int init_idle_threads(int ncpu)
2006{ 2033{
2007 int i; 2034 int i, ret;
2008 2035
2009 idle_threads = zalloc(ncpu * sizeof(struct thread *)); 2036 idle_threads = zalloc(ncpu * sizeof(struct thread *));
2010 if (!idle_threads) 2037 if (!idle_threads)
@@ -2018,7 +2045,9 @@ static int init_idle_threads(int ncpu)
2018 if (idle_threads[i] == NULL) 2045 if (idle_threads[i] == NULL)
2019 return -ENOMEM; 2046 return -ENOMEM;
2020 2047
2021 thread__set_comm(idle_threads[i], idle_comm, 0); 2048 ret = init_idle_thread(idle_threads[i]);
2049 if (ret < 0)
2050 return ret;
2022 } 2051 }
2023 2052
2024 return 0; 2053 return 0;
@@ -2065,14 +2094,23 @@ static struct thread *get_idle_thread(int cpu)
2065 idle_threads[cpu] = thread__new(0, 0); 2094 idle_threads[cpu] = thread__new(0, 0);
2066 2095
2067 if (idle_threads[cpu]) { 2096 if (idle_threads[cpu]) {
2068 idle_threads[cpu]->tid = 0; 2097 if (init_idle_thread(idle_threads[cpu]) < 0)
2069 thread__set_comm(idle_threads[cpu], idle_comm, 0); 2098 return NULL;
2070 } 2099 }
2071 } 2100 }
2072 2101
2073 return idle_threads[cpu]; 2102 return idle_threads[cpu];
2074} 2103}
2075 2104
2105static void save_idle_callchain(struct idle_thread_runtime *itr,
2106 struct perf_sample *sample)
2107{
2108 if (!symbol_conf.use_callchain || sample->callchain == NULL)
2109 return;
2110
2111 callchain_cursor__copy(&itr->cursor, &callchain_cursor);
2112}
2113
2076/* 2114/*
2077 * handle runtime stats saved per thread 2115 * handle runtime stats saved per thread
2078 */ 2116 */
@@ -2111,7 +2149,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
2111{ 2149{
2112 struct thread *thread; 2150 struct thread *thread;
2113 2151
2114 if (is_idle_sample(sched, sample, evsel, machine)) { 2152 if (is_idle_sample(sample, evsel)) {
2115 thread = get_idle_thread(sample->cpu); 2153 thread = get_idle_thread(sample->cpu);
2116 if (thread == NULL) 2154 if (thread == NULL)
2117 pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu); 2155 pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
@@ -2124,13 +2162,37 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
2124 pr_debug("Failed to get thread for tid %d. skipping sample.\n", 2162 pr_debug("Failed to get thread for tid %d. skipping sample.\n",
2125 sample->tid); 2163 sample->tid);
2126 } 2164 }
2165
2166 save_task_callchain(sched, sample, evsel, machine);
2167 if (sched->idle_hist) {
2168 struct thread *idle;
2169 struct idle_thread_runtime *itr;
2170
2171 idle = get_idle_thread(sample->cpu);
2172 if (idle == NULL) {
2173 pr_err("Failed to get idle thread for cpu %d.\n", sample->cpu);
2174 return NULL;
2175 }
2176
2177 itr = thread__priv(idle);
2178 if (itr == NULL)
2179 return NULL;
2180
2181 itr->last_thread = thread;
2182
2183 /* copy task callchain when entering to idle */
2184 if (perf_evsel__intval(evsel, sample, "next_pid") == 0)
2185 save_idle_callchain(itr, sample);
2186 }
2127 } 2187 }
2128 2188
2129 return thread; 2189 return thread;
2130} 2190}
2131 2191
2132static bool timehist_skip_sample(struct perf_sched *sched, 2192static bool timehist_skip_sample(struct perf_sched *sched,
2133 struct thread *thread) 2193 struct thread *thread,
2194 struct perf_evsel *evsel,
2195 struct perf_sample *sample)
2134{ 2196{
2135 bool rc = false; 2197 bool rc = false;
2136 2198
@@ -2139,10 +2201,19 @@ static bool timehist_skip_sample(struct perf_sched *sched,
2139 sched->skipped_samples++; 2201 sched->skipped_samples++;
2140 } 2202 }
2141 2203
2204 if (sched->idle_hist) {
2205 if (strcmp(perf_evsel__name(evsel), "sched:sched_switch"))
2206 rc = true;
2207 else if (perf_evsel__intval(evsel, sample, "prev_pid") != 0 &&
2208 perf_evsel__intval(evsel, sample, "next_pid") != 0)
2209 rc = true;
2210 }
2211
2142 return rc; 2212 return rc;
2143} 2213}
2144 2214
2145static void timehist_print_wakeup_event(struct perf_sched *sched, 2215static void timehist_print_wakeup_event(struct perf_sched *sched,
2216 struct perf_evsel *evsel,
2146 struct perf_sample *sample, 2217 struct perf_sample *sample,
2147 struct machine *machine, 2218 struct machine *machine,
2148 struct thread *awakened) 2219 struct thread *awakened)
@@ -2155,8 +2226,8 @@ static void timehist_print_wakeup_event(struct perf_sched *sched,
2155 return; 2226 return;
2156 2227
2157 /* show wakeup unless both awakee and awaker are filtered */ 2228 /* show wakeup unless both awakee and awaker are filtered */
2158 if (timehist_skip_sample(sched, thread) && 2229 if (timehist_skip_sample(sched, thread, evsel, sample) &&
2159 timehist_skip_sample(sched, awakened)) { 2230 timehist_skip_sample(sched, awakened, evsel, sample)) {
2160 return; 2231 return;
2161 } 2232 }
2162 2233
@@ -2201,7 +2272,7 @@ static int timehist_sched_wakeup_event(struct perf_tool *tool,
2201 /* show wakeups if requested */ 2272 /* show wakeups if requested */
2202 if (sched->show_wakeups && 2273 if (sched->show_wakeups &&
2203 !perf_time__skip_sample(&sched->ptime, sample->time)) 2274 !perf_time__skip_sample(&sched->ptime, sample->time))
2204 timehist_print_wakeup_event(sched, sample, machine, thread); 2275 timehist_print_wakeup_event(sched, evsel, sample, machine, thread);
2205 2276
2206 return 0; 2277 return 0;
2207} 2278}
@@ -2228,8 +2299,8 @@ static void timehist_print_migration_event(struct perf_sched *sched,
2228 if (thread == NULL) 2299 if (thread == NULL)
2229 return; 2300 return;
2230 2301
2231 if (timehist_skip_sample(sched, thread) && 2302 if (timehist_skip_sample(sched, thread, evsel, sample) &&
2232 timehist_skip_sample(sched, migrated)) { 2303 timehist_skip_sample(sched, migrated, evsel, sample)) {
2233 return; 2304 return;
2234 } 2305 }
2235 2306
@@ -2314,7 +2385,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2314 goto out; 2385 goto out;
2315 } 2386 }
2316 2387
2317 if (timehist_skip_sample(sched, thread)) 2388 if (timehist_skip_sample(sched, thread, evsel, sample))
2318 goto out; 2389 goto out;
2319 2390
2320 tr = thread__get_runtime(thread); 2391 tr = thread__get_runtime(thread);
@@ -2350,7 +2421,39 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2350 t = ptime->end; 2421 t = ptime->end;
2351 } 2422 }
2352 2423
2353 timehist_update_runtime_stats(tr, t, tprev); 2424 if (!sched->idle_hist || thread->tid == 0) {
2425 timehist_update_runtime_stats(tr, t, tprev);
2426
2427 if (sched->idle_hist) {
2428 struct idle_thread_runtime *itr = (void *)tr;
2429 struct thread_runtime *last_tr;
2430
2431 BUG_ON(thread->tid != 0);
2432
2433 if (itr->last_thread == NULL)
2434 goto out;
2435
2436 /* add current idle time as last thread's runtime */
2437 last_tr = thread__get_runtime(itr->last_thread);
2438 if (last_tr == NULL)
2439 goto out;
2440
2441 timehist_update_runtime_stats(last_tr, t, tprev);
2442 /*
2443 * remove delta time of last thread as it's not updated
2444 * and otherwise it will show an invalid value next
2445 * time. we only care total run time and run stat.
2446 */
2447 last_tr->dt_run = 0;
2448 last_tr->dt_wait = 0;
2449 last_tr->dt_delay = 0;
2450
2451 if (itr->cursor.nr)
2452 callchain_append(&itr->callchain, &itr->cursor, t - tprev);
2453
2454 itr->last_thread = NULL;
2455 }
2456 }
2354 2457
2355 if (!sched->summary_only) 2458 if (!sched->summary_only)
2356 timehist_print_sample(sched, sample, &al, thread, t); 2459 timehist_print_sample(sched, sample, &al, thread, t);
@@ -2457,6 +2560,60 @@ static int show_deadthread_runtime(struct thread *t, void *priv)
2457 return __show_thread_runtime(t, priv); 2560 return __show_thread_runtime(t, priv);
2458} 2561}
2459 2562
2563static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
2564{
2565 const char *sep = " <- ";
2566 struct callchain_list *chain;
2567 size_t ret = 0;
2568 char bf[1024];
2569 bool first;
2570
2571 if (node == NULL)
2572 return 0;
2573
2574 ret = callchain__fprintf_folded(fp, node->parent);
2575 first = (ret == 0);
2576
2577 list_for_each_entry(chain, &node->val, list) {
2578 if (chain->ip >= PERF_CONTEXT_MAX)
2579 continue;
2580 if (chain->ms.sym && chain->ms.sym->ignore)
2581 continue;
2582 ret += fprintf(fp, "%s%s", first ? "" : sep,
2583 callchain_list__sym_name(chain, bf, sizeof(bf),
2584 false));
2585 first = false;
2586 }
2587
2588 return ret;
2589}
2590
2591static size_t timehist_print_idlehist_callchain(struct rb_root *root)
2592{
2593 size_t ret = 0;
2594 FILE *fp = stdout;
2595 struct callchain_node *chain;
2596 struct rb_node *rb_node = rb_first(root);
2597
2598 printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains");
2599 printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line,
2600 graph_dotted_line);
2601
2602 while (rb_node) {
2603 chain = rb_entry(rb_node, struct callchain_node, rb_node);
2604 rb_node = rb_next(rb_node);
2605
2606 ret += fprintf(fp, " ");
2607 print_sched_time(chain->hit, 12);
2608 ret += 16; /* print_sched_time returns 2nd arg + 4 */
2609 ret += fprintf(fp, " %8d ", chain->count);
2610 ret += callchain__fprintf_folded(fp, chain);
2611 ret += fprintf(fp, "\n");
2612 }
2613
2614 return ret;
2615}
2616
2460static void timehist_print_summary(struct perf_sched *sched, 2617static void timehist_print_summary(struct perf_sched *sched,
2461 struct perf_session *session) 2618 struct perf_session *session)
2462{ 2619{
@@ -2472,9 +2629,15 @@ static void timehist_print_summary(struct perf_sched *sched,
2472 if (comm_width < 30) 2629 if (comm_width < 30)
2473 comm_width = 30; 2630 comm_width = 30;
2474 2631
2475 printf("\nRuntime summary\n"); 2632 if (sched->idle_hist) {
2476 printf("%*s parent sched-in ", comm_width, "comm"); 2633 printf("\nIdle-time summary\n");
2477 printf(" run-time min-run avg-run max-run stddev migrations\n"); 2634 printf("%*s parent sched-out ", comm_width, "comm");
2635 printf(" idle-time min-idle avg-idle max-idle stddev migrations\n");
2636 } else {
2637 printf("\nRuntime summary\n");
2638 printf("%*s parent sched-in ", comm_width, "comm");
2639 printf(" run-time min-run avg-run max-run stddev migrations\n");
2640 }
2478 printf("%*s (count) ", comm_width, ""); 2641 printf("%*s (count) ", comm_width, "");
2479 printf(" (msec) (msec) (msec) (msec) %%\n"); 2642 printf(" (msec) (msec) (msec) (msec) %%\n");
2480 printf("%.117s\n", graph_dotted_line); 2643 printf("%.117s\n", graph_dotted_line);
@@ -2490,7 +2653,7 @@ static void timehist_print_summary(struct perf_sched *sched,
2490 printf("<no terminated tasks>\n"); 2653 printf("<no terminated tasks>\n");
2491 2654
2492 /* CPU idle stats not tracked when samples were skipped */ 2655 /* CPU idle stats not tracked when samples were skipped */
2493 if (sched->skipped_samples) 2656 if (sched->skipped_samples && !sched->idle_hist)
2494 return; 2657 return;
2495 2658
2496 printf("\nIdle stats:\n"); 2659 printf("\nIdle stats:\n");
@@ -2509,6 +2672,35 @@ static void timehist_print_summary(struct perf_sched *sched,
2509 printf(" CPU %2d idle entire time window\n", i); 2672 printf(" CPU %2d idle entire time window\n", i);
2510 } 2673 }
2511 2674
2675 if (sched->idle_hist && symbol_conf.use_callchain) {
2676 callchain_param.mode = CHAIN_FOLDED;
2677 callchain_param.value = CCVAL_PERIOD;
2678
2679 callchain_register_param(&callchain_param);
2680
2681 printf("\nIdle stats by callchain:\n");
2682 for (i = 0; i < idle_max_cpu; ++i) {
2683 struct idle_thread_runtime *itr;
2684
2685 t = idle_threads[i];
2686 if (!t)
2687 continue;
2688
2689 itr = thread__priv(t);
2690 if (itr == NULL)
2691 continue;
2692
2693 callchain_param.sort(&itr->sorted_root, &itr->callchain,
2694 0, &callchain_param);
2695
2696 printf(" CPU %2d:", i);
2697 print_sched_time(itr->tr.total_run_time, 6);
2698 printf(" msec\n");
2699 timehist_print_idlehist_callchain(&itr->sorted_root);
2700 printf("\n");
2701 }
2702 }
2703
2512 printf("\n" 2704 printf("\n"
2513 " Total number of unique tasks: %" PRIu64 "\n" 2705 " Total number of unique tasks: %" PRIu64 "\n"
2514 "Total number of context switches: %" PRIu64 "\n" 2706 "Total number of context switches: %" PRIu64 "\n"
@@ -3036,6 +3228,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3036 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), 3228 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
3037 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), 3229 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
3038 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), 3230 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
3231 OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
3039 OPT_STRING(0, "time", &sched.time_str, "str", 3232 OPT_STRING(0, "time", &sched.time_str, "str",
3040 "Time span for analysis (start,stop)"), 3233 "Time span for analysis (start,stop)"),
3041 OPT_PARENT(sched_options) 3234 OPT_PARENT(sched_options)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 688dea7cb08f..a02f2e965628 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2195,7 +2195,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
2195} 2195}
2196 2196
2197static 2197static
2198int process_stat_config_event(struct perf_tool *tool __maybe_unused, 2198int process_stat_config_event(struct perf_tool *tool,
2199 union perf_event *event, 2199 union perf_event *event,
2200 struct perf_session *session __maybe_unused) 2200 struct perf_session *session __maybe_unused)
2201{ 2201{
@@ -2238,7 +2238,7 @@ static int set_maps(struct perf_stat *st)
2238} 2238}
2239 2239
2240static 2240static
2241int process_thread_map_event(struct perf_tool *tool __maybe_unused, 2241int process_thread_map_event(struct perf_tool *tool,
2242 union perf_event *event, 2242 union perf_event *event,
2243 struct perf_session *session __maybe_unused) 2243 struct perf_session *session __maybe_unused)
2244{ 2244{
@@ -2257,7 +2257,7 @@ int process_thread_map_event(struct perf_tool *tool __maybe_unused,
2257} 2257}
2258 2258
2259static 2259static
2260int process_cpu_map_event(struct perf_tool *tool __maybe_unused, 2260int process_cpu_map_event(struct perf_tool *tool,
2261 union perf_event *event, 2261 union perf_event *event,
2262 struct perf_session *session __maybe_unused) 2262 struct perf_session *session __maybe_unused)
2263{ 2263{
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
new file mode 100755
index 000000000000..c747bfd7f14d
--- /dev/null
+++ b/tools/perf/check-headers.sh
@@ -0,0 +1,59 @@
1#!/bin/sh
2
3HEADERS='
4include/uapi/linux/perf_event.h
5include/linux/hash.h
6include/uapi/linux/hw_breakpoint.h
7arch/x86/include/asm/disabled-features.h
8arch/x86/include/asm/required-features.h
9arch/x86/include/asm/cpufeatures.h
10arch/arm/include/uapi/asm/perf_regs.h
11arch/arm64/include/uapi/asm/perf_regs.h
12arch/powerpc/include/uapi/asm/perf_regs.h
13arch/x86/include/uapi/asm/perf_regs.h
14arch/x86/include/uapi/asm/kvm.h
15arch/x86/include/uapi/asm/kvm_perf.h
16arch/x86/include/uapi/asm/svm.h
17arch/x86/include/uapi/asm/vmx.h
18arch/powerpc/include/uapi/asm/kvm.h
19arch/s390/include/uapi/asm/kvm.h
20arch/s390/include/uapi/asm/kvm_perf.h
21arch/s390/include/uapi/asm/sie.h
22arch/arm/include/uapi/asm/kvm.h
23arch/arm64/include/uapi/asm/kvm.h
24include/asm-generic/bitops/arch_hweight.h
25include/asm-generic/bitops/const_hweight.h
26include/asm-generic/bitops/__fls.h
27include/asm-generic/bitops/fls.h
28include/asm-generic/bitops/fls64.h
29include/linux/coresight-pmu.h
30include/uapi/asm-generic/mman-common.h
31'
32
33check () {
34 file=$1
35 opts=
36
37 shift
38 while [ -n "$*" ]; do
39 opts="$opts \"$1\""
40 shift
41 done
42
43 cmd="diff $opts ../$file ../../$file > /dev/null"
44
45 test -f ../../$file &&
46 eval $cmd || echo "Warning: $file differs from kernel" >&2
47}
48
49
50# simple diff check
51for i in $HEADERS; do
52 check $i -B
53done
54
55# diff with extra ignore lines
56check arch/x86/lib/memcpy_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
57check arch/x86/lib/memset_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
58check include/uapi/asm-generic/mman.h -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>"
59check include/uapi/linux/mman.h -B -I "^#include <\(uapi/\)*asm/mman.h>"
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 9a0236a4cf95..1c27d947c2fe 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -55,6 +55,7 @@ struct record_opts {
55 bool all_user; 55 bool all_user;
56 bool tail_synthesize; 56 bool tail_synthesize;
57 bool overwrite; 57 bool overwrite;
58 bool ignore_missing_thread;
58 unsigned int freq; 59 unsigned int freq;
59 unsigned int mmap_pages; 60 unsigned int mmap_pages;
60 unsigned int auxtrace_mmap_pages; 61 unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 23605202d4a1..a77dcc0d24e3 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -186,6 +186,10 @@ static struct test generic_tests[] = {
186 .func = test__thread_map_synthesize, 186 .func = test__thread_map_synthesize,
187 }, 187 },
188 { 188 {
189 .desc = "Remove thread map",
190 .func = test__thread_map_remove,
191 },
192 {
189 .desc = "Synthesize cpu map", 193 .desc = "Synthesize cpu map",
190 .func = test__cpu_map_synthesize, 194 .func = test__cpu_map_synthesize,
191 }, 195 },
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0d7b251305af..a512f0c8ff5b 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -80,6 +80,7 @@ const char *test__bpf_subtest_get_desc(int subtest);
80int test__bpf_subtest_get_nr(void); 80int test__bpf_subtest_get_nr(void);
81int test_session_topology(int subtest); 81int test_session_topology(int subtest);
82int test__thread_map_synthesize(int subtest); 82int test__thread_map_synthesize(int subtest);
83int test__thread_map_remove(int subtest);
83int test__cpu_map_synthesize(int subtest); 84int test__cpu_map_synthesize(int subtest);
84int test__synthesize_stat_config(int subtest); 85int test__synthesize_stat_config(int subtest);
85int test__synthesize_stat(int subtest); 86int test__synthesize_stat(int subtest);
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index cee2a2cdc933..a4a4b4625ac3 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -1,3 +1,4 @@
1#include <stdlib.h>
1#include <sys/types.h> 2#include <sys/types.h>
2#include <unistd.h> 3#include <unistd.h>
3#include <sys/prctl.h> 4#include <sys/prctl.h>
@@ -93,3 +94,46 @@ int test__thread_map_synthesize(int subtest __maybe_unused)
93 94
94 return 0; 95 return 0;
95} 96}
97
98int test__thread_map_remove(int subtest __maybe_unused)
99{
100 struct thread_map *threads;
101 char *str;
102 int i;
103
104 TEST_ASSERT_VAL("failed to allocate map string",
105 asprintf(&str, "%d,%d", getpid(), getppid()) >= 0);
106
107 threads = thread_map__new_str(str, NULL, 0);
108
109 TEST_ASSERT_VAL("failed to allocate thread_map",
110 threads);
111
112 if (verbose)
113 thread_map__fprintf(threads, stderr);
114
115 TEST_ASSERT_VAL("failed to remove thread",
116 !thread_map__remove(threads, 0));
117
118 TEST_ASSERT_VAL("thread_map count != 1", threads->nr == 1);
119
120 if (verbose)
121 thread_map__fprintf(threads, stderr);
122
123 TEST_ASSERT_VAL("failed to remove thread",
124 !thread_map__remove(threads, 0));
125
126 TEST_ASSERT_VAL("thread_map count != 0", threads->nr == 0);
127
128 if (verbose)
129 thread_map__fprintf(threads, stderr);
130
131 TEST_ASSERT_VAL("failed to not remove thread",
132 thread_map__remove(threads, 0));
133
134 for (i = 0; i < threads->nr; i++)
135 free(threads->map[i].comm);
136
137 free(threads);
138 return 0;
139}
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c
index fd710ab33684..af1cfde6b97b 100644
--- a/tools/perf/trace/beauty/mmap.c
+++ b/tools/perf/trace/beauty/mmap.c
@@ -42,7 +42,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
42 42
43 P_MMAP_FLAG(SHARED); 43 P_MMAP_FLAG(SHARED);
44 P_MMAP_FLAG(PRIVATE); 44 P_MMAP_FLAG(PRIVATE);
45#ifdef MAP_32BIT
45 P_MMAP_FLAG(32BIT); 46 P_MMAP_FLAG(32BIT);
47#endif
46 P_MMAP_FLAG(ANONYMOUS); 48 P_MMAP_FLAG(ANONYMOUS);
47 P_MMAP_FLAG(DENYWRITE); 49 P_MMAP_FLAG(DENYWRITE);
48 P_MMAP_FLAG(EXECUTABLE); 50 P_MMAP_FLAG(EXECUTABLE);
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index ec7a30fad149..ba36aac340bc 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -215,7 +215,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
215 ui_browser__set_color(browser, color); 215 ui_browser__set_color(browser, color);
216 if (dl->ins.ops && dl->ins.ops->scnprintf) { 216 if (dl->ins.ops && dl->ins.ops->scnprintf) {
217 if (ins__is_jump(&dl->ins)) { 217 if (ins__is_jump(&dl->ins)) {
218 bool fwd = dl->ops.target.offset > (u64)dl->offset; 218 bool fwd = dl->ops.target.offset > dl->offset;
219 219
220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
221 SLSMG_UARROW_CHAR); 221 SLSMG_UARROW_CHAR);
@@ -245,7 +245,8 @@ static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sy
245{ 245{
246 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) 246 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
247 || !disasm_line__has_offset(dl) 247 || !disasm_line__has_offset(dl)
248 || dl->ops.target.offset >= symbol__size(sym)) 248 || dl->ops.target.offset < 0
249 || dl->ops.target.offset >= (s64)symbol__size(sym))
249 return false; 250 return false;
250 251
251 return true; 252 return true;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index ea7e0de4b9c1..06cc04e5806a 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -223,13 +223,19 @@ bool ins__is_call(const struct ins *ins)
223static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) 223static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused)
224{ 224{
225 const char *s = strchr(ops->raw, '+'); 225 const char *s = strchr(ops->raw, '+');
226 const char *c = strchr(ops->raw, ',');
226 227
227 ops->target.addr = strtoull(ops->raw, NULL, 16); 228 if (c++ != NULL)
229 ops->target.addr = strtoull(c, NULL, 16);
230 else
231 ops->target.addr = strtoull(ops->raw, NULL, 16);
228 232
229 if (s++ != NULL) 233 if (s++ != NULL) {
230 ops->target.offset = strtoull(s, NULL, 16); 234 ops->target.offset = strtoull(s, NULL, 16);
231 else 235 ops->target.offset_avail = true;
232 ops->target.offset = UINT64_MAX; 236 } else {
237 ops->target.offset_avail = false;
238 }
233 239
234 return 0; 240 return 0;
235} 241}
@@ -237,7 +243,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
237static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 243static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
238 struct ins_operands *ops) 244 struct ins_operands *ops)
239{ 245{
240 if (!ops->target.addr) 246 if (!ops->target.addr || ops->target.offset < 0)
241 return ins__raw_scnprintf(ins, bf, size, ops); 247 return ins__raw_scnprintf(ins, bf, size, ops);
242 248
243 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); 249 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
@@ -641,7 +647,8 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
641 647
642 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 648 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
643 649
644 if (addr < sym->start || addr >= sym->end) { 650 if ((addr < sym->start || addr >= sym->end) &&
651 (addr != sym->end || sym->start != sym->end)) {
645 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", 652 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
646 __func__, __LINE__, sym->name, sym->start, addr, sym->end); 653 __func__, __LINE__, sym->name, sym->start, addr, sym->end);
647 return -ERANGE; 654 return -ERANGE;
@@ -1205,9 +1212,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1205 if (dl == NULL) 1212 if (dl == NULL)
1206 return -1; 1213 return -1;
1207 1214
1208 if (dl->ops.target.offset == UINT64_MAX) 1215 if (!disasm_line__has_offset(dl)) {
1209 dl->ops.target.offset = dl->ops.target.addr - 1216 dl->ops.target.offset = dl->ops.target.addr -
1210 map__rip_2objdump(map, sym->start); 1217 map__rip_2objdump(map, sym->start);
1218 dl->ops.target.offset_avail = true;
1219 }
1211 1220
1212 /* kcore has no symbols, so add the call target name */ 1221 /* kcore has no symbols, so add the call target name */
1213 if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) { 1222 if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) {
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 87e4cadc5d27..09776b5af991 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -24,7 +24,8 @@ struct ins_operands {
24 char *raw; 24 char *raw;
25 char *name; 25 char *name;
26 u64 addr; 26 u64 addr;
27 u64 offset; 27 s64 offset;
28 bool offset_avail;
28 } target; 29 } target;
29 union { 30 union {
30 struct { 31 struct {
@@ -68,7 +69,7 @@ struct disasm_line {
68 69
69static inline bool disasm_line__has_offset(const struct disasm_line *dl) 70static inline bool disasm_line__has_offset(const struct disasm_line *dl)
70{ 71{
71 return dl->ops.target.offset != UINT64_MAX; 72 return dl->ops.target.offset_avail;
72} 73}
73 74
74void disasm_line__free(struct disasm_line *dl); 75void disasm_line__free(struct disasm_line *dl);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b2365a63db45..04e536ae4d88 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -990,6 +990,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
990 * it overloads any global configuration. 990 * it overloads any global configuration.
991 */ 991 */
992 apply_config_terms(evsel, opts); 992 apply_config_terms(evsel, opts);
993
994 evsel->ignore_missing_thread = opts->ignore_missing_thread;
993} 995}
994 996
995static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 997static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -1419,6 +1421,33 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val,
1419 return fprintf(fp, " %-32s %s\n", name, val); 1421 return fprintf(fp, " %-32s %s\n", name, val);
1420} 1422}
1421 1423
1424static bool ignore_missing_thread(struct perf_evsel *evsel,
1425 struct thread_map *threads,
1426 int thread, int err)
1427{
1428 if (!evsel->ignore_missing_thread)
1429 return false;
1430
1431 /* The system wide setup does not work with threads. */
1432 if (evsel->system_wide)
1433 return false;
1434
1435 /* The -ESRCH is perf event syscall errno for pid's not found. */
1436 if (err != -ESRCH)
1437 return false;
1438
1439 /* If there's only one thread, let it fail. */
1440 if (threads->nr == 1)
1441 return false;
1442
1443 if (thread_map__remove(threads, thread))
1444 return false;
1445
1446 pr_warning("WARNING: Ignored open failure for pid %d\n",
1447 thread_map__pid(threads, thread));
1448 return true;
1449}
1450
1422static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1451static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
1423 struct thread_map *threads) 1452 struct thread_map *threads)
1424{ 1453{
@@ -1474,7 +1503,7 @@ retry_sample_id:
1474 for (cpu = 0; cpu < cpus->nr; cpu++) { 1503 for (cpu = 0; cpu < cpus->nr; cpu++) {
1475 1504
1476 for (thread = 0; thread < nthreads; thread++) { 1505 for (thread = 0; thread < nthreads; thread++) {
1477 int group_fd; 1506 int fd, group_fd;
1478 1507
1479 if (!evsel->cgrp && !evsel->system_wide) 1508 if (!evsel->cgrp && !evsel->system_wide)
1480 pid = thread_map__pid(threads, thread); 1509 pid = thread_map__pid(threads, thread);
@@ -1484,21 +1513,37 @@ retry_open:
1484 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", 1513 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx",
1485 pid, cpus->map[cpu], group_fd, flags); 1514 pid, cpus->map[cpu], group_fd, flags);
1486 1515
1487 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 1516 fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu],
1488 pid, 1517 group_fd, flags);
1489 cpus->map[cpu], 1518
1490 group_fd, flags); 1519 FD(evsel, cpu, thread) = fd;
1491 if (FD(evsel, cpu, thread) < 0) { 1520
1521 if (fd < 0) {
1492 err = -errno; 1522 err = -errno;
1523
1524 if (ignore_missing_thread(evsel, threads, thread, err)) {
1525 /*
1526 * We just removed 1 thread, so take a step
1527 * back on thread index and lower the upper
1528 * nthreads limit.
1529 */
1530 nthreads--;
1531 thread--;
1532
1533 /* ... and pretend like nothing have happened. */
1534 err = 0;
1535 continue;
1536 }
1537
1493 pr_debug2("\nsys_perf_event_open failed, error %d\n", 1538 pr_debug2("\nsys_perf_event_open failed, error %d\n",
1494 err); 1539 err);
1495 goto try_fallback; 1540 goto try_fallback;
1496 } 1541 }
1497 1542
1498 pr_debug2(" = %d\n", FD(evsel, cpu, thread)); 1543 pr_debug2(" = %d\n", fd);
1499 1544
1500 if (evsel->bpf_fd >= 0) { 1545 if (evsel->bpf_fd >= 0) {
1501 int evt_fd = FD(evsel, cpu, thread); 1546 int evt_fd = fd;
1502 int bpf_fd = evsel->bpf_fd; 1547 int bpf_fd = evsel->bpf_fd;
1503 1548
1504 err = ioctl(evt_fd, 1549 err = ioctl(evt_fd,
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 6abb89cd27f9..06ef6f29efa1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -120,6 +120,7 @@ struct perf_evsel {
120 bool tracking; 120 bool tracking;
121 bool per_pkg; 121 bool per_pkg;
122 bool precise_max; 122 bool precise_max;
123 bool ignore_missing_thread;
123 /* parse modifier helper */ 124 /* parse modifier helper */
124 int exclude_GH; 125 int exclude_GH;
125 int nr_members; 126 int nr_members;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index df2482b2ba45..dc93940de351 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1459,7 +1459,8 @@ int dso__load(struct dso *dso, struct map *map)
1459 * Read the build id if possible. This is required for 1459 * Read the build id if possible. This is required for
1460 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1460 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1461 */ 1461 */
1462 if (is_regular_file(dso->long_name) && 1462 if (!dso->has_build_id &&
1463 is_regular_file(dso->long_name) &&
1463 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) 1464 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
1464 dso__set_build_id(dso, build_id); 1465 dso__set_build_id(dso, build_id);
1465 1466
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 40585f5b7027..f9eab200fd75 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -448,3 +448,25 @@ bool thread_map__has(struct thread_map *threads, pid_t pid)
448 448
449 return false; 449 return false;
450} 450}
451
452int thread_map__remove(struct thread_map *threads, int idx)
453{
454 int i;
455
456 if (threads->nr < 1)
457 return -EINVAL;
458
459 if (idx >= threads->nr)
460 return -EINVAL;
461
462 /*
463 * Free the 'idx' item and shift the rest up.
464 */
465 free(threads->map[idx].comm);
466
467 for (i = idx; i < threads->nr - 1; i++)
468 threads->map[i] = threads->map[i + 1];
469
470 threads->nr--;
471 return 0;
472}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index bd3b971588da..ea0ef08c6303 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -58,4 +58,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread)
58 58
59void thread_map__read_comms(struct thread_map *threads); 59void thread_map__read_comms(struct thread_map *threads);
60bool thread_map__has(struct thread_map *threads, pid_t pid); 60bool thread_map__has(struct thread_map *threads, pid_t pid);
61int thread_map__remove(struct thread_map *threads, int idx);
61#endif /* __PERF_THREAD_MAP_H */ 62#endif /* __PERF_THREAD_MAP_H */