aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt30
-rw-r--r--tools/perf/Documentation/perf-timechart.txt41
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/Makefile.perf20
-rw-r--r--tools/perf/builtin-annotate.c5
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-inject.c2
-rw-r--r--tools/perf/builtin-probe.c23
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-report.c210
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-top.c90
-rw-r--r--tools/perf/config/Makefile9
-rw-r--r--tools/perf/perf.c9
-rw-r--r--tools/perf/tests/builtin-test.c46
-rw-r--r--tools/perf/tests/dso-data.c214
-rw-r--r--tools/perf/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/tests/hists_common.c52
-rw-r--r--tools/perf/tests/hists_common.h32
-rw-r--r--tools/perf/tests/hists_cumulate.c726
-rw-r--r--tools/perf/tests/hists_filter.c39
-rw-r--r--tools/perf/tests/hists_link.c36
-rw-r--r--tools/perf/tests/hists_output.c31
-rw-r--r--tools/perf/tests/make7
-rw-r--r--tools/perf/tests/tests.h3
-rw-r--r--tools/perf/ui/browser.c2
-rw-r--r--tools/perf/ui/browsers/hists.c73
-rw-r--r--tools/perf/ui/gtk/hists.c33
-rw-r--r--tools/perf/ui/hist.c119
-rw-r--r--tools/perf/ui/stdio/hist.c8
-rw-r--r--tools/perf/util/callchain.c45
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/dso.c279
-rw-r--r--tools/perf/util/dso.h50
-rw-r--r--tools/perf/util/dwarf-aux.c7
-rw-r--r--tools/perf/util/event.c57
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/evsel.c5
-rw-r--r--tools/perf/util/hist.c490
-rw-r--r--tools/perf/util/hist.h58
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/map.c4
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/perf_regs.c10
-rw-r--r--tools/perf/util/perf_regs.h4
-rw-r--r--tools/perf/util/probe-event.c13
-rw-r--r--tools/perf/util/probe-finder.c15
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/sort.c214
-rw-r--r--tools/perf/util/sort.h22
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/unwind-libunwind.c2
-rw-r--r--tools/perf/util/util.c1
-rw-r--r--tools/perf/util/util.h1
57 files changed, 2702 insertions, 500 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index c71b0f36d9e8..d460049cae8e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -184,9 +184,10 @@ following filters are defined:
184 - in_tx: only when the target is in a hardware transaction 184 - in_tx: only when the target is in a hardware transaction
185 - no_tx: only when the target is not in a hardware transaction 185 - no_tx: only when the target is not in a hardware transaction
186 - abort_tx: only when the target is a hardware transaction abort 186 - abort_tx: only when the target is a hardware transaction abort
187 - cond: conditional branches
187 188
188+ 189+
189The option requires at least one branch type among any, any_call, any_ret, ind_call. 190The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
190The privilege levels may be omitted, in which case, the privilege levels of the associated 191The privilege levels may be omitted, in which case, the privilege levels of the associated
191event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege 192event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
192levels are subject to permissions. When sampling on multiple events, branch stack sampling 193levels are subject to permissions. When sampling on multiple events, branch stack sampling
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index a1b5185402d5..d2b59af62bc0 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -111,12 +111,28 @@ OPTIONS
111--fields=:: 111--fields=::
112 Specify output field - multiple keys can be specified in CSV format. 112 Specify output field - multiple keys can be specified in CSV format.
113 Following fields are available: 113 Following fields are available:
114 overhead, overhead_sys, overhead_us, sample and period. 114 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
115 Also it can contain any sort key(s). 115 Also it can contain any sort key(s).
116 116
117 By default, every sort keys not specified in -F will be appended 117 By default, every sort keys not specified in -F will be appended
118 automatically. 118 automatically.
119 119
120 If --mem-mode option is used, following sort keys are also available
121 (incompatible with --branch-stack):
122 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
123
124 - symbol_daddr: name of data symbol being executed on at the time of sample
125 - dso_daddr: name of library or module containing the data being executed
126 on at the time of sample
127 - locked: whether the bus was locked at the time of sample
128 - tlb: type of tlb access for the data at the time of sample
129 - mem: type of memory access for the data at the time of sample
130 - snoop: type of snoop (if any) for the data at the time of sample
131 - dcacheline: the cacheline the data address is on at the time of sample
132
133 And default sort keys are changed to local_weight, mem, sym, dso,
134 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
135
120-p:: 136-p::
121--parent=<regex>:: 137--parent=<regex>::
122 A regex filter to identify parent. The parent is a caller of this 138 A regex filter to identify parent. The parent is a caller of this
@@ -163,6 +179,11 @@ OPTIONS
163 179
164 Default: fractal,0.5,callee,function. 180 Default: fractal,0.5,callee,function.
165 181
182--children::
183 Accumulate callchain of children to parent entry so that then can
184 show up in the output. The output will have a new "Children" column
185 and will be sorted on the data. It requires callchains are recorded.
186
166--max-stack:: 187--max-stack::
167 Set the stack depth limit when parsing the callchain, anything 188 Set the stack depth limit when parsing the callchain, anything
168 beyond the specified depth will be ignored. This is a trade-off 189 beyond the specified depth will be ignored. This is a trade-off
@@ -255,6 +276,13 @@ OPTIONS
255 Demangle symbol names to human readable form. It's enabled by default, 276 Demangle symbol names to human readable form. It's enabled by default,
256 disable with --no-demangle. 277 disable with --no-demangle.
257 278
279--mem-mode::
280 Use the data addresses of samples in addition to instruction addresses
281 to build the histograms. To generate meaningful output, the perf.data
282 file must have been obtained using perf record -d -W and using a
283 special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
284 'perf mem' for simpler access.
285
258--percent-limit:: 286--percent-limit::
259 Do not show entries which have an overhead under that percent. 287 Do not show entries which have an overhead under that percent.
260 (Default: 0). 288 (Default: 0).
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index bc5990c33dc0..5e0f986dff38 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -43,27 +43,6 @@ TIMECHART OPTIONS
43 43
44--symfs=<directory>:: 44--symfs=<directory>::
45 Look for files with symbols relative to this directory. 45 Look for files with symbols relative to this directory.
46
47EXAMPLES
48--------
49
50$ perf timechart record git pull
51
52 [ perf record: Woken up 13 times to write data ]
53 [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
54
55$ perf timechart
56
57 Written 10.2 seconds of trace to output.svg.
58
59Record system-wide timechart:
60
61 $ perf timechart record
62
63 then generate timechart and highlight 'gcc' tasks:
64
65 $ perf timechart --highlight gcc
66
67-n:: 46-n::
68--proc-num:: 47--proc-num::
69 Print task info for at least given number of tasks. 48 Print task info for at least given number of tasks.
@@ -88,6 +67,26 @@ RECORD OPTIONS
88--callchain:: 67--callchain::
89 Do call-graph (stack chain/backtrace) recording 68 Do call-graph (stack chain/backtrace) recording
90 69
70EXAMPLES
71--------
72
73$ perf timechart record git pull
74
75 [ perf record: Woken up 13 times to write data ]
76 [ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
77
78$ perf timechart
79
80 Written 10.2 seconds of trace to output.svg.
81
82Record system-wide timechart:
83
84 $ perf timechart record
85
86 then generate timechart and highlight 'gcc' tasks:
87
88 $ perf timechart --highlight gcc
89
91SEE ALSO 90SEE ALSO
92-------- 91--------
93linkperf:perf-record[1] 92linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index dcfa54c851e9..180ae02137a5 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -119,7 +119,7 @@ Default is to monitor all CPUS.
119--fields=:: 119--fields=::
120 Specify output field - multiple keys can be specified in CSV format. 120 Specify output field - multiple keys can be specified in CSV format.
121 Following fields are available: 121 Following fields are available:
122 overhead, overhead_sys, overhead_us, sample and period. 122 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
123 Also it can contain any sort key(s). 123 Also it can contain any sort key(s).
124 124
125 By default, every sort keys not specified in --field will be appended 125 By default, every sort keys not specified in --field will be appended
@@ -161,6 +161,12 @@ Default is to monitor all CPUS.
161 Setup and enable call-graph (stack chain/backtrace) recording, 161 Setup and enable call-graph (stack chain/backtrace) recording,
162 implies -g. 162 implies -g.
163 163
164--children::
165 Accumulate callchain of children to parent entry so that then can
166 show up in the output. The output will have a new "Children" column
167 and will be sorted on the data. It requires -g/--call-graph option
168 enabled.
169
164--max-stack:: 170--max-stack::
165 Set the stack depth limit when parsing the callchain, anything 171 Set the stack depth limit when parsing the callchain, anything
166 beyond the specified depth will be ignored. This is a trade-off 172 beyond the specified depth will be ignored. This is a trade-off
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 02f0a4dd1a80..9670a16fa577 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -400,6 +400,7 @@ LIB_OBJS += $(OUTPUT)tests/hists_common.o
400LIB_OBJS += $(OUTPUT)tests/hists_link.o 400LIB_OBJS += $(OUTPUT)tests/hists_link.o
401LIB_OBJS += $(OUTPUT)tests/hists_filter.o 401LIB_OBJS += $(OUTPUT)tests/hists_filter.o
402LIB_OBJS += $(OUTPUT)tests/hists_output.o 402LIB_OBJS += $(OUTPUT)tests/hists_output.o
403LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o
403LIB_OBJS += $(OUTPUT)tests/python-use.o 404LIB_OBJS += $(OUTPUT)tests/python-use.o
404LIB_OBJS += $(OUTPUT)tests/bp_signal.o 405LIB_OBJS += $(OUTPUT)tests/bp_signal.o
405LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 406LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
@@ -788,8 +789,8 @@ help:
788 @echo '' 789 @echo ''
789 @echo 'Perf install targets:' 790 @echo 'Perf install targets:'
790 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' 791 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
791 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular' 792 @echo ' HINT: use "prefix" or "DESTDIR" to install to a particular'
792 @echo ' path like make prefix=/usr/local install install-doc' 793 @echo ' path like "make prefix=/usr/local install install-doc"'
793 @echo ' install - install compiled binaries' 794 @echo ' install - install compiled binaries'
794 @echo ' install-doc - install *all* documentation' 795 @echo ' install-doc - install *all* documentation'
795 @echo ' install-man - install manpage documentation' 796 @echo ' install-man - install manpage documentation'
@@ -814,17 +815,20 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
814$(DOC_TARGETS): 815$(DOC_TARGETS):
815 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) 816 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
816 817
818TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol
819TAG_FILES= ../../include/uapi/linux/perf_event.h
820
817TAGS: 821TAGS:
818 $(RM) TAGS 822 $(QUIET_GEN)$(RM) TAGS; \
819 $(FIND) . -name '*.[hcS]' -print | xargs etags -a 823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES)
820 824
821tags: 825tags:
822 $(RM) tags 826 $(QUIET_GEN)$(RM) tags; \
823 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a 827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES)
824 828
825cscope: 829cscope:
826 $(RM) cscope* 830 $(QUIET_GEN)$(RM) cscope*; \
827 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b 831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES)
828 832
829### Detect prefix changes 833### Detect prefix changes
830TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 834TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index d30d2c2e2a7a..1ec429fef2be 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -65,12 +65,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
65 return 0; 65 return 0;
66 } 66 }
67 67
68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0); 68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0,
69 true);
69 if (he == NULL) 70 if (he == NULL)
70 return -ENOMEM; 71 return -ENOMEM;
71 72
72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 73 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 74 hists__inc_nr_samples(&evsel->hists, true);
74 return ret; 75 return ret;
75} 76}
76 77
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 8bff543acaab..9a5a035cb426 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -315,7 +315,7 @@ static int hists__add_entry(struct hists *hists,
315 u64 weight, u64 transaction) 315 u64 weight, u64 transaction)
316{ 316{
317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, 317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
318 transaction) != NULL) 318 transaction, true) != NULL)
319 return 0; 319 return 0;
320 return -ENOMEM; 320 return -ENOMEM;
321} 321}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6a3af0013d68..16c7c11ad06e 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -72,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
72 if (ret) 72 if (ret)
73 return ret; 73 return ret;
74 74
75 if (&inject->output.is_pipe) 75 if (!inject->output.is_pipe)
76 return 0; 76 return 0;
77 77
78 return perf_event__repipe_synth(tool, event); 78 return perf_event__repipe_synth(tool, event);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index cdcd4eb3a57d..c63fa2925075 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -288,6 +288,13 @@ static void cleanup_params(void)
288 memset(&params, 0, sizeof(params)); 288 memset(&params, 0, sizeof(params));
289} 289}
290 290
291static void pr_err_with_code(const char *msg, int err)
292{
293 pr_err("%s", msg);
294 pr_debug(" Reason: %s (Code: %d)", strerror(-err), err);
295 pr_err("\n");
296}
297
291static int 298static int
292__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 299__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
293{ 300{
@@ -379,7 +386,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
379 } 386 }
380 ret = parse_probe_event_argv(argc, argv); 387 ret = parse_probe_event_argv(argc, argv);
381 if (ret < 0) { 388 if (ret < 0) {
382 pr_err(" Error: Parse Error. (%d)\n", ret); 389 pr_err_with_code(" Error: Command Parse Error.", ret);
383 return ret; 390 return ret;
384 } 391 }
385 } 392 }
@@ -419,8 +426,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
419 } 426 }
420 ret = show_perf_probe_events(); 427 ret = show_perf_probe_events();
421 if (ret < 0) 428 if (ret < 0)
422 pr_err(" Error: Failed to show event list. (%d)\n", 429 pr_err_with_code(" Error: Failed to show event list.", ret);
423 ret);
424 return ret; 430 return ret;
425 } 431 }
426 if (params.show_funcs) { 432 if (params.show_funcs) {
@@ -445,8 +451,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
445 strfilter__delete(params.filter); 451 strfilter__delete(params.filter);
446 params.filter = NULL; 452 params.filter = NULL;
447 if (ret < 0) 453 if (ret < 0)
448 pr_err(" Error: Failed to show functions." 454 pr_err_with_code(" Error: Failed to show functions.", ret);
449 " (%d)\n", ret);
450 return ret; 455 return ret;
451 } 456 }
452 457
@@ -464,7 +469,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
464 469
465 ret = show_line_range(&params.line_range, params.target); 470 ret = show_line_range(&params.line_range, params.target);
466 if (ret < 0) 471 if (ret < 0)
467 pr_err(" Error: Failed to show lines. (%d)\n", ret); 472 pr_err_with_code(" Error: Failed to show lines.", ret);
468 return ret; 473 return ret;
469 } 474 }
470 if (params.show_vars) { 475 if (params.show_vars) {
@@ -485,7 +490,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
485 strfilter__delete(params.filter); 490 strfilter__delete(params.filter);
486 params.filter = NULL; 491 params.filter = NULL;
487 if (ret < 0) 492 if (ret < 0)
488 pr_err(" Error: Failed to show vars. (%d)\n", ret); 493 pr_err_with_code(" Error: Failed to show vars.", ret);
489 return ret; 494 return ret;
490 } 495 }
491#endif 496#endif
@@ -493,7 +498,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
493 if (params.dellist) { 498 if (params.dellist) {
494 ret = del_perf_probe_events(params.dellist); 499 ret = del_perf_probe_events(params.dellist);
495 if (ret < 0) { 500 if (ret < 0) {
496 pr_err(" Error: Failed to delete events. (%d)\n", ret); 501 pr_err_with_code(" Error: Failed to delete events.", ret);
497 return ret; 502 return ret;
498 } 503 }
499 } 504 }
@@ -504,7 +509,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
504 params.target, 509 params.target,
505 params.force_add); 510 params.force_add);
506 if (ret < 0) { 511 if (ret < 0) {
507 pr_err(" Error: Failed to add events. (%d)\n", ret); 512 pr_err_with_code(" Error: Failed to add events.", ret);
508 return ret; 513 return ret;
509 } 514 }
510 } 515 }
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e4c85b8f46c2..378b85b731a7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -454,7 +454,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
454 if (done) 454 if (done)
455 break; 455 break;
456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
457 if (err < 0 && errno == EINTR) 457 /*
458 * Propagate error, only if there's any. Ignore positive
459 * number of returned events and interrupt error.
460 */
461 if (err > 0 || (err < 0 && errno == EINTR))
458 err = 0; 462 err = 0;
459 waking++; 463 waking++;
460 } 464 }
@@ -544,6 +548,7 @@ static const struct branch_mode branch_modes[] = {
544 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 548 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
545 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 549 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
546 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 550 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
551 BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
547 BRANCH_END 552 BRANCH_END
548}; 553};
549 554
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index bc0eec1ce4be..21d830bafff3 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -72,6 +72,10 @@ static int report__config(const char *var, const char *value, void *cb)
72 rep->min_percent = strtof(value, NULL); 72 rep->min_percent = strtof(value, NULL);
73 return 0; 73 return 0;
74 } 74 }
75 if (!strcmp(var, "report.children")) {
76 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
77 return 0;
78 }
75 79
76 return perf_default_config(var, value, cb); 80 return perf_default_config(var, value, cb);
77} 81}
@@ -85,156 +89,52 @@ static void report__inc_stats(struct report *rep, struct hist_entry *he)
85 */ 89 */
86 if (he->stat.nr_events == 1) 90 if (he->stat.nr_events == 1)
87 rep->nr_entries++; 91 rep->nr_entries++;
88
89 /*
90 * Only counts number of samples at this stage as it's more
91 * natural to do it here and non-sample events are also
92 * counted in perf_session_deliver_event(). The dump_trace
93 * requires this info is ready before going to the output tree.
94 */
95 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
96 if (!he->filtered)
97 he->hists->stats.nr_non_filtered_samples++;
98} 92}
99 93
100static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, 94static int hist_iter__report_callback(struct hist_entry_iter *iter,
101 struct perf_sample *sample, struct perf_evsel *evsel) 95 struct addr_location *al, bool single,
96 void *arg)
102{ 97{
103 struct symbol *parent = NULL; 98 int err = 0;
104 struct hist_entry *he; 99 struct report *rep = arg;
105 struct mem_info *mi, *mx; 100 struct hist_entry *he = iter->he;
106 uint64_t cost; 101 struct perf_evsel *evsel = iter->evsel;
107 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); 102 struct mem_info *mi;
108 103 struct branch_info *bi;
109 if (err)
110 return err;
111 104
112 mi = sample__resolve_mem(sample, al); 105 report__inc_stats(rep, he);
113 if (!mi)
114 return -ENOMEM;
115 106
116 if (rep->hide_unresolved && !al->sym) 107 if (!ui__has_annotation())
117 return 0; 108 return 0;
118 109
119 cost = sample->weight; 110 if (sort__mode == SORT_MODE__BRANCH) {
120 if (!cost) 111 bi = he->branch_info;
121 cost = 1; 112 err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
122
123 /*
124 * must pass period=weight in order to get the correct
125 * sorting from hists__collapse_resort() which is solely
126 * based on periods. We want sorting be done on nr_events * weight
127 * and this is indirectly achieved by passing period=weight here
128 * and the he_stat__add_period() function.
129 */
130 he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
131 cost, cost, 0);
132 if (!he)
133 return -ENOMEM;
134
135 if (ui__has_annotation()) {
136 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
137 if (err)
138 goto out;
139
140 mx = he->mem_info;
141 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
142 if (err) 113 if (err)
143 goto out; 114 goto out;
144 }
145
146 report__inc_stats(rep, he);
147
148 err = hist_entry__append_callchain(he, sample);
149out:
150 return err;
151}
152
153static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
154 struct perf_sample *sample, struct perf_evsel *evsel)
155{
156 struct symbol *parent = NULL;
157 unsigned i;
158 struct hist_entry *he;
159 struct branch_info *bi, *bx;
160 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
161 115
162 if (err) 116 err = addr_map_symbol__inc_samples(&bi->to, evsel->idx);
163 return err;
164
165 bi = sample__resolve_bstack(sample, al);
166 if (!bi)
167 return -ENOMEM;
168
169 for (i = 0; i < sample->branch_stack->nr; i++) {
170 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
171 continue;
172 117
173 err = -ENOMEM; 118 } else if (rep->mem_mode) {
174 119 mi = he->mem_info;
175 /* overwrite the 'al' to branch-to info */ 120 err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx);
176 al->map = bi[i].to.map; 121 if (err)
177 al->sym = bi[i].to.sym;
178 al->addr = bi[i].to.addr;
179 /*
180 * The report shows the percentage of total branches captured
181 * and not events sampled. Thus we use a pseudo period of 1.
182 */
183 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
184 1, 1, 0);
185 if (he) {
186 if (ui__has_annotation()) {
187 bx = he->branch_info;
188 err = addr_map_symbol__inc_samples(&bx->from,
189 evsel->idx);
190 if (err)
191 goto out;
192
193 err = addr_map_symbol__inc_samples(&bx->to,
194 evsel->idx);
195 if (err)
196 goto out;
197 }
198 report__inc_stats(rep, he);
199 } else
200 goto out; 122 goto out;
201 }
202 err = 0;
203out:
204 free(bi);
205 return err;
206}
207
208static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
209 struct addr_location *al, struct perf_sample *sample)
210{
211 struct symbol *parent = NULL;
212 struct hist_entry *he;
213 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
214
215 if (err)
216 return err;
217 123
218 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
219 sample->period, sample->weight,
220 sample->transaction);
221 if (he == NULL)
222 return -ENOMEM;
223
224 err = hist_entry__append_callchain(he, sample);
225 if (err)
226 goto out;
227
228 if (ui__has_annotation())
229 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 124 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
230 125
231 report__inc_stats(rep, he); 126 } else if (symbol_conf.cumulate_callchain) {
127 if (single)
128 err = hist_entry__inc_addr_samples(he, evsel->idx,
129 al->addr);
130 } else {
131 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
132 }
232 133
233out: 134out:
234 return err; 135 return err;
235} 136}
236 137
237
238static int process_sample_event(struct perf_tool *tool, 138static int process_sample_event(struct perf_tool *tool,
239 union perf_event *event, 139 union perf_event *event,
240 struct perf_sample *sample, 140 struct perf_sample *sample,
@@ -243,6 +143,10 @@ static int process_sample_event(struct perf_tool *tool,
243{ 143{
244 struct report *rep = container_of(tool, struct report, tool); 144 struct report *rep = container_of(tool, struct report, tool);
245 struct addr_location al; 145 struct addr_location al;
146 struct hist_entry_iter iter = {
147 .hide_unresolved = rep->hide_unresolved,
148 .add_entry_cb = hist_iter__report_callback,
149 };
246 int ret; 150 int ret;
247 151
248 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 152 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
@@ -257,22 +161,23 @@ static int process_sample_event(struct perf_tool *tool,
257 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 161 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
258 return 0; 162 return 0;
259 163
260 if (sort__mode == SORT_MODE__BRANCH) { 164 if (sort__mode == SORT_MODE__BRANCH)
261 ret = report__add_branch_hist_entry(rep, &al, sample, evsel); 165 iter.ops = &hist_iter_branch;
262 if (ret < 0) 166 else if (rep->mem_mode)
263 pr_debug("problem adding lbr entry, skipping event\n"); 167 iter.ops = &hist_iter_mem;
264 } else if (rep->mem_mode == 1) { 168 else if (symbol_conf.cumulate_callchain)
265 ret = report__add_mem_hist_entry(rep, &al, sample, evsel); 169 iter.ops = &hist_iter_cumulative;
266 if (ret < 0) 170 else
267 pr_debug("problem adding mem entry, skipping event\n"); 171 iter.ops = &hist_iter_normal;
268 } else { 172
269 if (al.map != NULL) 173 if (al.map != NULL)
270 al.map->dso->hit = 1; 174 al.map->dso->hit = 1;
175
176 ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack,
177 rep);
178 if (ret < 0)
179 pr_debug("problem adding hist entry, skipping event\n");
271 180
272 ret = report__add_hist_entry(rep, evsel, &al, sample);
273 if (ret < 0)
274 pr_debug("problem incrementing symbol period, skipping event\n");
275 }
276 return ret; 181 return ret;
277} 182}
278 183
@@ -329,6 +234,14 @@ static int report__setup_sample_type(struct report *rep)
329 } 234 }
330 } 235 }
331 236
237 if (symbol_conf.cumulate_callchain) {
238 /* Silently ignore if callchain is missing */
239 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
240 symbol_conf.cumulate_callchain = false;
241 perf_hpp__cancel_cumulate();
242 }
243 }
244
332 if (sort__mode == SORT_MODE__BRANCH) { 245 if (sort__mode == SORT_MODE__BRANCH) {
333 if (!is_pipe && 246 if (!is_pipe &&
334 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 247 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
@@ -712,6 +625,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
712 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 625 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
713 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 626 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
714 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt), 627 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
628 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
629 "Accumulate callchains of children and show total overhead as well"),
715 OPT_INTEGER(0, "max-stack", &report.max_stack, 630 OPT_INTEGER(0, "max-stack", &report.max_stack,
716 "Set the maximum stack depth when parsing the callchain, " 631 "Set the maximum stack depth when parsing the callchain, "
717 "anything beyond the specified depth will be ignored. " 632 "anything beyond the specified depth will be ignored. "
@@ -804,8 +719,10 @@ repeat:
804 has_br_stack = perf_header__has_feat(&session->header, 719 has_br_stack = perf_header__has_feat(&session->header,
805 HEADER_BRANCH_STACK); 720 HEADER_BRANCH_STACK);
806 721
807 if (branch_mode == -1 && has_br_stack) 722 if (branch_mode == -1 && has_br_stack) {
808 sort__mode = SORT_MODE__BRANCH; 723 sort__mode = SORT_MODE__BRANCH;
724 symbol_conf.cumulate_callchain = false;
725 }
809 726
810 if (report.mem_mode) { 727 if (report.mem_mode) {
811 if (sort__mode == SORT_MODE__BRANCH) { 728 if (sort__mode == SORT_MODE__BRANCH) {
@@ -813,6 +730,7 @@ repeat:
813 goto error; 730 goto error;
814 } 731 }
815 sort__mode = SORT_MODE__MEMORY; 732 sort__mode = SORT_MODE__MEMORY;
733 symbol_conf.cumulate_callchain = false;
816 } 734 }
817 735
818 if (setup_sorting() < 0) { 736 if (setup_sorting() < 0) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d7176830b9b2..c38d06c04775 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1428,7 +1428,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1428 int err = 0; 1428 int err = 0;
1429 1429
1430 evsel->hists.stats.total_period += sample->period; 1430 evsel->hists.stats.total_period += sample->period;
1431 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1431 hists__inc_nr_samples(&evsel->hists, true);
1432 1432
1433 if (evsel->handler != NULL) { 1433 if (evsel->handler != NULL) {
1434 tracepoint_handler f = evsel->handler; 1434 tracepoint_handler f = evsel->handler;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5b389ce4cd15..377971dc89a3 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
196 196
197 pthread_mutex_unlock(&notes->lock); 197 pthread_mutex_unlock(&notes->lock);
198 198
199 /*
200 * This function is now called with he->hists->lock held.
201 * Release it before going to sleep.
202 */
203 pthread_mutex_unlock(&he->hists->lock);
204
199 if (err == -ERANGE && !he->ms.map->erange_warned) 205 if (err == -ERANGE && !he->ms.map->erange_warned)
200 ui__warn_map_erange(he->ms.map, sym, ip); 206 ui__warn_map_erange(he->ms.map, sym, ip);
201 else if (err == -ENOMEM) { 207 else if (err == -ENOMEM) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top,
203 sym->name); 209 sym->name);
204 sleep(1); 210 sleep(1);
205 } 211 }
212
213 pthread_mutex_lock(&he->hists->lock);
206} 214}
207 215
208static void perf_top__show_details(struct perf_top *top) 216static void perf_top__show_details(struct perf_top *top)
@@ -238,27 +246,6 @@ out_unlock:
238 pthread_mutex_unlock(&notes->lock); 246 pthread_mutex_unlock(&notes->lock);
239} 247}
240 248
241static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
242 struct addr_location *al,
243 struct perf_sample *sample)
244{
245 struct hist_entry *he;
246
247 pthread_mutex_lock(&evsel->hists.lock);
248 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
249 sample->period, sample->weight,
250 sample->transaction);
251 pthread_mutex_unlock(&evsel->hists.lock);
252 if (he == NULL)
253 return NULL;
254
255 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
256 if (!he->filtered)
257 evsel->hists.stats.nr_non_filtered_samples++;
258
259 return he;
260}
261
262static void perf_top__print_sym_table(struct perf_top *top) 249static void perf_top__print_sym_table(struct perf_top *top)
263{ 250{
264 char bf[160]; 251 char bf[160];
@@ -662,6 +649,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
662 return 0; 649 return 0;
663} 650}
664 651
652static int hist_iter__top_callback(struct hist_entry_iter *iter,
653 struct addr_location *al, bool single,
654 void *arg)
655{
656 struct perf_top *top = arg;
657 struct hist_entry *he = iter->he;
658 struct perf_evsel *evsel = iter->evsel;
659
660 if (sort__has_sym && single) {
661 u64 ip = al->addr;
662
663 if (al->map)
664 ip = al->map->unmap_ip(al->map, ip);
665
666 perf_top__record_precise_ip(top, he, evsel->idx, ip);
667 }
668
669 return 0;
670}
671
665static void perf_event__process_sample(struct perf_tool *tool, 672static void perf_event__process_sample(struct perf_tool *tool,
666 const union perf_event *event, 673 const union perf_event *event,
667 struct perf_evsel *evsel, 674 struct perf_evsel *evsel,
@@ -669,8 +676,6 @@ static void perf_event__process_sample(struct perf_tool *tool,
669 struct machine *machine) 676 struct machine *machine)
670{ 677{
671 struct perf_top *top = container_of(tool, struct perf_top, tool); 678 struct perf_top *top = container_of(tool, struct perf_top, tool);
672 struct symbol *parent = NULL;
673 u64 ip = sample->ip;
674 struct addr_location al; 679 struct addr_location al;
675 int err; 680 int err;
676 681
@@ -745,25 +750,23 @@ static void perf_event__process_sample(struct perf_tool *tool,
745 } 750 }
746 751
747 if (al.sym == NULL || !al.sym->ignore) { 752 if (al.sym == NULL || !al.sym->ignore) {
748 struct hist_entry *he; 753 struct hist_entry_iter iter = {
754 .add_entry_cb = hist_iter__top_callback,
755 };
749 756
750 err = sample__resolve_callchain(sample, &parent, evsel, &al, 757 if (symbol_conf.cumulate_callchain)
751 top->max_stack); 758 iter.ops = &hist_iter_cumulative;
752 if (err) 759 else
753 return; 760 iter.ops = &hist_iter_normal;
754 761
755 he = perf_evsel__add_hist_entry(evsel, &al, sample); 762 pthread_mutex_lock(&evsel->hists.lock);
756 if (he == NULL) {
757 pr_err("Problem incrementing symbol period, skipping event\n");
758 return;
759 }
760 763
761 err = hist_entry__append_callchain(he, sample); 764 err = hist_entry_iter__add(&iter, &al, evsel, sample,
762 if (err) 765 top->max_stack, top);
763 return; 766 if (err < 0)
767 pr_err("Problem incrementing symbol period, skipping event\n");
764 768
765 if (sort__has_sym) 769 pthread_mutex_unlock(&evsel->hists.lock);
766 perf_top__record_precise_ip(top, he, evsel->idx, ip);
767 } 770 }
768 771
769 return; 772 return;
@@ -1001,6 +1004,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)
1001 1004
1002 if (!strcmp(var, "top.call-graph")) 1005 if (!strcmp(var, "top.call-graph"))
1003 return record_parse_callchain(value, &top->record_opts); 1006 return record_parse_callchain(value, &top->record_opts);
1007 if (!strcmp(var, "top.children")) {
1008 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1009 return 0;
1010 }
1004 1011
1005 return perf_default_config(var, value, cb); 1012 return perf_default_config(var, value, cb);
1006} 1013}
@@ -1095,6 +1102,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1095 OPT_CALLBACK(0, "call-graph", &top.record_opts, 1102 OPT_CALLBACK(0, "call-graph", &top.record_opts,
1096 "mode[,dump_size]", record_callchain_help, 1103 "mode[,dump_size]", record_callchain_help,
1097 &parse_callchain_opt), 1104 &parse_callchain_opt),
1105 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
1106 "Accumulate callchains of children and show total overhead as well"),
1098 OPT_INTEGER(0, "max-stack", &top.max_stack, 1107 OPT_INTEGER(0, "max-stack", &top.max_stack,
1099 "Set the maximum stack depth when parsing the callchain. " 1108 "Set the maximum stack depth when parsing the callchain. "
1100 "Default: " __stringify(PERF_MAX_STACK_DEPTH)), 1109 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1200,6 +1209,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1200 1209
1201 top.sym_evsel = perf_evlist__first(top.evlist); 1210 top.sym_evsel = perf_evlist__first(top.evlist);
1202 1211
1212 if (!symbol_conf.use_callchain) {
1213 symbol_conf.cumulate_callchain = false;
1214 perf_hpp__cancel_cumulate();
1215 }
1216
1203 symbol_conf.priv_size = sizeof(struct annotation); 1217 symbol_conf.priv_size = sizeof(struct annotation);
1204 1218
1205 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1219 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 729bbdf5cec7..f30ac5e5d271 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -299,7 +299,11 @@ else
299 NO_LIBUNWIND := 1 299 NO_LIBUNWIND := 1
300 NO_LIBDW_DWARF_UNWIND := 1 300 NO_LIBDW_DWARF_UNWIND := 1
301 else 301 else
302 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 302 ifneq ($(filter s% -static%,$(LDFLAGS),),)
303 msg := $(error No static glibc found, please install glibc-static);
304 else
305 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
306 endif
303 endif 307 endif
304 else 308 else
305 ifndef NO_LIBDW_DWARF_UNWIND 309 ifndef NO_LIBDW_DWARF_UNWIND
@@ -447,6 +451,7 @@ else
447 ifneq ($(feature-libperl), 1) 451 ifneq ($(feature-libperl), 1)
448 CFLAGS += -DNO_LIBPERL 452 CFLAGS += -DNO_LIBPERL
449 NO_LIBPERL := 1 453 NO_LIBPERL := 1
454 msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed);
450 else 455 else
451 LDFLAGS += $(PERL_EMBED_LDFLAGS) 456 LDFLAGS += $(PERL_EMBED_LDFLAGS)
452 EXTLIBS += $(PERL_EMBED_LIBADD) 457 EXTLIBS += $(PERL_EMBED_LIBADD)
@@ -599,7 +604,7 @@ endif
599 604
600# Make the path relative to DESTDIR, not to prefix 605# Make the path relative to DESTDIR, not to prefix
601ifndef DESTDIR 606ifndef DESTDIR
602prefix = $(HOME) 607prefix ?= $(HOME)
603endif 608endif
604bindir_relative = bin 609bindir_relative = bin
605bindir = $(prefix)/$(bindir_relative) 610bindir = $(prefix)/$(bindir_relative)
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 431798a4110d..95c58fc15284 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -458,6 +458,7 @@ int main(int argc, const char **argv)
458 458
459 /* The page_size is placed in util object. */ 459 /* The page_size is placed in util object. */
460 page_size = sysconf(_SC_PAGE_SIZE); 460 page_size = sysconf(_SC_PAGE_SIZE);
461 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
461 462
462 cmd = perf_extract_argv0_path(argv[0]); 463 cmd = perf_extract_argv0_path(argv[0]);
463 if (!cmd) 464 if (!cmd)
@@ -481,14 +482,18 @@ int main(int argc, const char **argv)
481 fprintf(stderr, "cannot handle %s internally", cmd); 482 fprintf(stderr, "cannot handle %s internally", cmd);
482 goto out; 483 goto out;
483 } 484 }
484#ifdef HAVE_LIBAUDIT_SUPPORT
485 if (!prefixcmp(cmd, "trace")) { 485 if (!prefixcmp(cmd, "trace")) {
486#ifdef HAVE_LIBAUDIT_SUPPORT
486 set_buildid_dir(); 487 set_buildid_dir();
487 setup_path(); 488 setup_path();
488 argv[0] = "trace"; 489 argv[0] = "trace";
489 return cmd_trace(argc, argv, NULL); 490 return cmd_trace(argc, argv, NULL);
490 } 491#else
492 fprintf(stderr,
493 "trace command not available: missing audit-libs devel package at build time.\n");
494 goto out;
491#endif 495#endif
496 }
492 /* Look for flags.. */ 497 /* Look for flags.. */
493 argv++; 498 argv++;
494 argc--; 499 argc--;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 831f52cae197..6f8b01bc6033 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * Builtin regression testing command: ever growing number of sanity tests 4 * Builtin regression testing command: ever growing number of sanity tests
5 */ 5 */
6#include <unistd.h>
7#include <string.h>
6#include "builtin.h" 8#include "builtin.h"
7#include "intlist.h" 9#include "intlist.h"
8#include "tests.h" 10#include "tests.h"
@@ -50,10 +52,18 @@ static struct test {
50 .func = test__pmu, 52 .func = test__pmu,
51 }, 53 },
52 { 54 {
53 .desc = "Test dso data interface", 55 .desc = "Test dso data read",
54 .func = test__dso_data, 56 .func = test__dso_data,
55 }, 57 },
56 { 58 {
59 .desc = "Test dso data cache",
60 .func = test__dso_data_cache,
61 },
62 {
63 .desc = "Test dso data reopen",
64 .func = test__dso_data_reopen,
65 },
66 {
57 .desc = "roundtrip evsel->name check", 67 .desc = "roundtrip evsel->name check",
58 .func = test__perf_evsel__roundtrip_name_test, 68 .func = test__perf_evsel__roundtrip_name_test,
59 }, 69 },
@@ -140,6 +150,10 @@ static struct test {
140 .func = test__hists_output, 150 .func = test__hists_output,
141 }, 151 },
142 { 152 {
153 .desc = "Test cumulation of child hist entries",
154 .func = test__hists_cumulate,
155 },
156 {
143 .func = NULL, 157 .func = NULL,
144 }, 158 },
145}; 159};
@@ -168,6 +182,34 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
168 return false; 182 return false;
169} 183}
170 184
185static int run_test(struct test *test)
186{
187 int status, err = -1, child = fork();
188
189 if (child < 0) {
190 pr_err("failed to fork test: %s\n", strerror(errno));
191 return -1;
192 }
193
194 if (!child) {
195 pr_debug("test child forked, pid %d\n", getpid());
196 err = test->func();
197 exit(err);
198 }
199
200 wait(&status);
201
202 if (WIFEXITED(status)) {
203 err = WEXITSTATUS(status);
204 pr_debug("test child finished with %d\n", err);
205 } else if (WIFSIGNALED(status)) {
206 err = -1;
207 pr_debug("test child interrupted\n");
208 }
209
210 return err;
211}
212
171static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 213static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
172{ 214{
173 int i = 0; 215 int i = 0;
@@ -196,7 +238,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
196 } 238 }
197 239
198 pr_debug("\n--- start ---\n"); 240 pr_debug("\n--- start ---\n");
199 err = tests[curr].func(); 241 err = run_test(&tests[curr]);
200 pr_debug("---- end ----\n%s:", tests[curr].desc); 242 pr_debug("---- end ----\n%s:", tests[curr].desc);
201 243
202 switch (err) { 244 switch (err) {
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 3e6cb171e3d3..630808cd7cc2 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -1,22 +1,27 @@
1#include "util.h"
2
3#include <stdlib.h> 1#include <stdlib.h>
4#include <linux/types.h> 2#include <linux/types.h>
5#include <sys/stat.h> 3#include <sys/stat.h>
6#include <fcntl.h> 4#include <fcntl.h>
7#include <string.h> 5#include <string.h>
8 6#include <sys/time.h>
7#include <sys/resource.h>
8#include <api/fs/fs.h>
9#include "util.h"
9#include "machine.h" 10#include "machine.h"
10#include "symbol.h" 11#include "symbol.h"
11#include "tests.h" 12#include "tests.h"
12 13
13static char *test_file(int size) 14static char *test_file(int size)
14{ 15{
15 static char buf_templ[] = "/tmp/test-XXXXXX"; 16#define TEMPL "/tmp/perf-test-XXXXXX"
17 static char buf_templ[sizeof(TEMPL)];
16 char *templ = buf_templ; 18 char *templ = buf_templ;
17 int fd, i; 19 int fd, i;
18 unsigned char *buf; 20 unsigned char *buf;
19 21
22 strcpy(buf_templ, TEMPL);
23#undef TEMPL
24
20 fd = mkstemp(templ); 25 fd = mkstemp(templ);
21 if (fd < 0) { 26 if (fd < 0) {
22 perror("mkstemp failed"); 27 perror("mkstemp failed");
@@ -150,3 +155,204 @@ int test__dso_data(void)
150 unlink(file); 155 unlink(file);
151 return 0; 156 return 0;
152} 157}
158
159static long open_files_cnt(void)
160{
161 char path[PATH_MAX];
162 struct dirent *dent;
163 DIR *dir;
164 long nr = 0;
165
166 scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint());
167 pr_debug("fd path: %s\n", path);
168
169 dir = opendir(path);
170 TEST_ASSERT_VAL("failed to open fd directory", dir);
171
172 while ((dent = readdir(dir)) != NULL) {
173 if (!strcmp(dent->d_name, ".") ||
174 !strcmp(dent->d_name, ".."))
175 continue;
176
177 nr++;
178 }
179
180 closedir(dir);
181 return nr - 1;
182}
183
184static struct dso **dsos;
185
186static int dsos__create(int cnt, int size)
187{
188 int i;
189
190 dsos = malloc(sizeof(dsos) * cnt);
191 TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
192
193 for (i = 0; i < cnt; i++) {
194 char *file;
195
196 file = test_file(size);
197 TEST_ASSERT_VAL("failed to get dso file", file);
198
199 dsos[i] = dso__new(file);
200 TEST_ASSERT_VAL("failed to get dso", dsos[i]);
201 }
202
203 return 0;
204}
205
206static void dsos__delete(int cnt)
207{
208 int i;
209
210 for (i = 0; i < cnt; i++) {
211 struct dso *dso = dsos[i];
212
213 unlink(dso->name);
214 dso__delete(dso);
215 }
216
217 free(dsos);
218}
219
220static int set_fd_limit(int n)
221{
222 struct rlimit rlim;
223
224 if (getrlimit(RLIMIT_NOFILE, &rlim))
225 return -1;
226
227 pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n);
228
229 rlim.rlim_cur = n;
230 return setrlimit(RLIMIT_NOFILE, &rlim);
231}
232
233int test__dso_data_cache(void)
234{
235 struct machine machine;
236 long nr_end, nr = open_files_cnt();
237 int dso_cnt, limit, i, fd;
238
239 memset(&machine, 0, sizeof(machine));
240
241 /* set as system limit */
242 limit = nr * 4;
243 TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
244
245 /* and this is now our dso open FDs limit + 1 extra */
246 dso_cnt = limit / 2 + 1;
247 TEST_ASSERT_VAL("failed to create dsos\n",
248 !dsos__create(dso_cnt, TEST_FILE_SIZE));
249
250 for (i = 0; i < (dso_cnt - 1); i++) {
251 struct dso *dso = dsos[i];
252
253 /*
254 * Open dsos via dso__data_fd or dso__data_read_offset.
255 * Both opens the data file and keep it open.
256 */
257 if (i % 2) {
258 fd = dso__data_fd(dso, &machine);
259 TEST_ASSERT_VAL("failed to get fd", fd > 0);
260 } else {
261 #define BUFSIZE 10
262 u8 buf[BUFSIZE];
263 ssize_t n;
264
265 n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE);
266 TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE);
267 }
268 }
269
270 /* open +1 dso over the allowed limit */
271 fd = dso__data_fd(dsos[i], &machine);
272 TEST_ASSERT_VAL("failed to get fd", fd > 0);
273
274 /* should force the first one to be closed */
275 TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1);
276
277 /* cleanup everything */
278 dsos__delete(dso_cnt);
279
280 /* Make sure we did not leak any file descriptor. */
281 nr_end = open_files_cnt();
282 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
283 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
284 return 0;
285}
286
287int test__dso_data_reopen(void)
288{
289 struct machine machine;
290 long nr_end, nr = open_files_cnt();
291 int fd, fd_extra;
292
293#define dso_0 (dsos[0])
294#define dso_1 (dsos[1])
295#define dso_2 (dsos[2])
296
297 memset(&machine, 0, sizeof(machine));
298
299 /*
300 * Test scenario:
301 * - create 3 dso objects
302 * - set process file descriptor limit to current
303 * files count + 3
304 * - test that the first dso gets closed when we
305 * reach the files count limit
306 */
307
308 /* Make sure we are able to open 3 fds anyway */
309 TEST_ASSERT_VAL("failed to set file limit",
310 !set_fd_limit((nr + 3)));
311
312 TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
313
314 /* open dso_0 */
315 fd = dso__data_fd(dso_0, &machine);
316 TEST_ASSERT_VAL("failed to get fd", fd > 0);
317
318 /* open dso_1 */
319 fd = dso__data_fd(dso_1, &machine);
320 TEST_ASSERT_VAL("failed to get fd", fd > 0);
321
322 /*
323 * open extra file descriptor and we just
324 * reached the files count limit
325 */
326 fd_extra = open("/dev/null", O_RDONLY);
327 TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0);
328
329 /* open dso_2 */
330 fd = dso__data_fd(dso_2, &machine);
331 TEST_ASSERT_VAL("failed to get fd", fd > 0);
332
333 /*
334 * dso_0 should get closed, because we reached
335 * the file descriptor limit
336 */
337 TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1);
338
339 /* open dso_0 */
340 fd = dso__data_fd(dso_0, &machine);
341 TEST_ASSERT_VAL("failed to get fd", fd > 0);
342
343 /*
344 * dso_1 should get closed, because we reached
345 * the file descriptor limit
346 */
347 TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1);
348
349 /* cleanup everything */
350 close(fd_extra);
351 dsos__delete(3);
352
353 /* Make sure we did not leak any file descriptor. */
354 nr_end = open_files_cnt();
355 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
356 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
357 return 0;
358}
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 108f0cd49f4e..96adb730b744 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -15,7 +15,7 @@ static int mmap_handler(struct perf_tool *tool __maybe_unused,
15 struct perf_sample *sample __maybe_unused, 15 struct perf_sample *sample __maybe_unused,
16 struct machine *machine) 16 struct machine *machine)
17{ 17{
18 return machine__process_mmap_event(machine, event, NULL); 18 return machine__process_mmap2_event(machine, event, NULL);
19} 19}
20 20
21static int init_live_machine(struct machine *machine) 21static int init_live_machine(struct machine *machine)
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index e4e01aadc3be..a62c09134516 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -12,9 +12,9 @@ static struct {
12 u32 pid; 12 u32 pid;
13 const char *comm; 13 const char *comm;
14} fake_threads[] = { 14} fake_threads[] = {
15 { 100, "perf" }, 15 { FAKE_PID_PERF1, "perf" },
16 { 200, "perf" }, 16 { FAKE_PID_PERF2, "perf" },
17 { 300, "bash" }, 17 { FAKE_PID_BASH, "bash" },
18}; 18};
19 19
20static struct { 20static struct {
@@ -22,15 +22,15 @@ static struct {
22 u64 start; 22 u64 start;
23 const char *filename; 23 const char *filename;
24} fake_mmap_info[] = { 24} fake_mmap_info[] = {
25 { 100, 0x40000, "perf" }, 25 { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" },
26 { 100, 0x50000, "libc" }, 26 { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" },
27 { 100, 0xf0000, "[kernel]" }, 27 { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" },
28 { 200, 0x40000, "perf" }, 28 { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" },
29 { 200, 0x50000, "libc" }, 29 { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" },
30 { 200, 0xf0000, "[kernel]" }, 30 { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" },
31 { 300, 0x40000, "bash" }, 31 { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" },
32 { 300, 0x50000, "libc" }, 32 { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" },
33 { 300, 0xf0000, "[kernel]" }, 33 { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" },
34}; 34};
35 35
36struct fake_sym { 36struct fake_sym {
@@ -40,27 +40,30 @@ struct fake_sym {
40}; 40};
41 41
42static struct fake_sym perf_syms[] = { 42static struct fake_sym perf_syms[] = {
43 { 700, 100, "main" }, 43 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
44 { 800, 100, "run_command" }, 44 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "run_command" },
45 { 900, 100, "cmd_record" }, 45 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "cmd_record" },
46}; 46};
47 47
48static struct fake_sym bash_syms[] = { 48static struct fake_sym bash_syms[] = {
49 { 700, 100, "main" }, 49 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
50 { 800, 100, "xmalloc" }, 50 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "xmalloc" },
51 { 900, 100, "xfree" }, 51 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "xfree" },
52}; 52};
53 53
54static struct fake_sym libc_syms[] = { 54static struct fake_sym libc_syms[] = {
55 { 700, 100, "malloc" }, 55 { 700, 100, "malloc" },
56 { 800, 100, "free" }, 56 { 800, 100, "free" },
57 { 900, 100, "realloc" }, 57 { 900, 100, "realloc" },
58 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "malloc" },
59 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "free" },
60 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "realloc" },
58}; 61};
59 62
60static struct fake_sym kernel_syms[] = { 63static struct fake_sym kernel_syms[] = {
61 { 700, 100, "schedule" }, 64 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "schedule" },
62 { 800, 100, "page_fault" }, 65 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "page_fault" },
63 { 900, 100, "sys_perf_event_open" }, 66 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "sys_perf_event_open" },
64}; 67};
65 68
66static struct { 69static struct {
@@ -102,7 +105,7 @@ struct machine *setup_fake_machine(struct machines *machines)
102 .pid = fake_mmap_info[i].pid, 105 .pid = fake_mmap_info[i].pid,
103 .tid = fake_mmap_info[i].pid, 106 .tid = fake_mmap_info[i].pid,
104 .start = fake_mmap_info[i].start, 107 .start = fake_mmap_info[i].start,
105 .len = 0x1000ULL, 108 .len = FAKE_MAP_LENGTH,
106 .pgoff = 0ULL, 109 .pgoff = 0ULL,
107 }, 110 },
108 }; 111 };
@@ -193,10 +196,11 @@ void print_hists_out(struct hists *hists)
193 he = rb_entry(node, struct hist_entry, rb_node); 196 he = rb_entry(node, struct hist_entry, rb_node);
194 197
195 if (!he->filtered) { 198 if (!he->filtered) {
196 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"\n", 199 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n",
197 i, thread__comm_str(he->thread), he->thread->tid, 200 i, thread__comm_str(he->thread), he->thread->tid,
198 he->ms.map->dso->short_name, 201 he->ms.map->dso->short_name,
199 he->ms.sym->name, he->stat.period); 202 he->ms.sym->name, he->stat.period,
203 he->stat_acc ? he->stat_acc->period : 0);
200 } 204 }
201 205
202 i++; 206 i++;
diff --git a/tools/perf/tests/hists_common.h b/tools/perf/tests/hists_common.h
index 1415ae69d7b6..888254e8665c 100644
--- a/tools/perf/tests/hists_common.h
+++ b/tools/perf/tests/hists_common.h
@@ -4,6 +4,34 @@
4struct machine; 4struct machine;
5struct machines; 5struct machines;
6 6
7#define FAKE_PID_PERF1 100
8#define FAKE_PID_PERF2 200
9#define FAKE_PID_BASH 300
10
11#define FAKE_MAP_PERF 0x400000
12#define FAKE_MAP_BASH 0x400000
13#define FAKE_MAP_LIBC 0x500000
14#define FAKE_MAP_KERNEL 0xf00000
15#define FAKE_MAP_LENGTH 0x100000
16
17#define FAKE_SYM_OFFSET1 700
18#define FAKE_SYM_OFFSET2 800
19#define FAKE_SYM_OFFSET3 900
20#define FAKE_SYM_LENGTH 100
21
22#define FAKE_IP_PERF_MAIN FAKE_MAP_PERF + FAKE_SYM_OFFSET1
23#define FAKE_IP_PERF_RUN_COMMAND FAKE_MAP_PERF + FAKE_SYM_OFFSET2
24#define FAKE_IP_PERF_CMD_RECORD FAKE_MAP_PERF + FAKE_SYM_OFFSET3
25#define FAKE_IP_BASH_MAIN FAKE_MAP_BASH + FAKE_SYM_OFFSET1
26#define FAKE_IP_BASH_XMALLOC FAKE_MAP_BASH + FAKE_SYM_OFFSET2
27#define FAKE_IP_BASH_XFREE FAKE_MAP_BASH + FAKE_SYM_OFFSET3
28#define FAKE_IP_LIBC_MALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET1
29#define FAKE_IP_LIBC_FREE FAKE_MAP_LIBC + FAKE_SYM_OFFSET2
30#define FAKE_IP_LIBC_REALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET3
31#define FAKE_IP_KERNEL_SCHEDULE FAKE_MAP_KERNEL + FAKE_SYM_OFFSET1
32#define FAKE_IP_KERNEL_PAGE_FAULT FAKE_MAP_KERNEL + FAKE_SYM_OFFSET2
33#define FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN FAKE_MAP_KERNEL + FAKE_SYM_OFFSET3
34
7/* 35/*
8 * The setup_fake_machine() provides a test environment which consists 36 * The setup_fake_machine() provides a test environment which consists
9 * of 3 processes that have 3 mappings and in turn, have 3 symbols 37 * of 3 processes that have 3 mappings and in turn, have 3 symbols
@@ -13,7 +41,7 @@ struct machines;
13 * ............. ............. ................... 41 * ............. ............. ...................
14 * perf: 100 perf main 42 * perf: 100 perf main
15 * perf: 100 perf run_command 43 * perf: 100 perf run_command
16 * perf: 100 perf comd_record 44 * perf: 100 perf cmd_record
17 * perf: 100 libc malloc 45 * perf: 100 libc malloc
18 * perf: 100 libc free 46 * perf: 100 libc free
19 * perf: 100 libc realloc 47 * perf: 100 libc realloc
@@ -22,7 +50,7 @@ struct machines;
22 * perf: 100 [kernel] sys_perf_event_open 50 * perf: 100 [kernel] sys_perf_event_open
23 * perf: 200 perf main 51 * perf: 200 perf main
24 * perf: 200 perf run_command 52 * perf: 200 perf run_command
25 * perf: 200 perf comd_record 53 * perf: 200 perf cmd_record
26 * perf: 200 libc malloc 54 * perf: 200 libc malloc
27 * perf: 200 libc free 55 * perf: 200 libc free
28 * perf: 200 libc realloc 56 * perf: 200 libc realloc
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
new file mode 100644
index 000000000000..0ac240db2e24
--- /dev/null
+++ b/tools/perf/tests/hists_cumulate.c
@@ -0,0 +1,726 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */
26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [perf] cmd_record() */
28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
29 /* perf [libc] malloc() */
30 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
31 /* perf [libc] free() */
32 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
33 /* perf [perf] main() */
34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
35 /* perf [kernel] page_fault() */
36 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
37 /* bash [bash] main() */
38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
39 /* bash [bash] xmalloc() */
40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
41 /* bash [kernel] page_fault() */
42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43};
44
45/*
46 * Will be casted to struct ip_callchain which has all 64 bit entries
47 * of nr and ips[].
48 */
49static u64 fake_callchains[][10] = {
50 /* schedule => run_command => main */
51 { 3, FAKE_IP_KERNEL_SCHEDULE, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
52 /* main */
53 { 1, FAKE_IP_PERF_MAIN, },
54 /* cmd_record => run_command => main */
55 { 3, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
56 /* malloc => cmd_record => run_command => main */
57 { 4, FAKE_IP_LIBC_MALLOC, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
58 FAKE_IP_PERF_MAIN, },
59 /* free => cmd_record => run_command => main */
60 { 4, FAKE_IP_LIBC_FREE, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
61 FAKE_IP_PERF_MAIN, },
62 /* main */
63 { 1, FAKE_IP_PERF_MAIN, },
64 /* page_fault => sys_perf_event_open => run_command => main */
65 { 4, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN,
66 FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
67 /* main */
68 { 1, FAKE_IP_BASH_MAIN, },
69 /* xmalloc => malloc => xmalloc => malloc => xmalloc => main */
70 { 6, FAKE_IP_BASH_XMALLOC, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC,
71 FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC, FAKE_IP_BASH_MAIN, },
72 /* page_fault => malloc => main */
73 { 3, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_MAIN, },
74};
75
76static int add_hist_entries(struct hists *hists, struct machine *machine)
77{
78 struct addr_location al;
79 struct perf_evsel *evsel = hists_to_evsel(hists);
80 struct perf_sample sample = { .period = 1000, };
81 size_t i;
82
83 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
84 const union perf_event event = {
85 .header = {
86 .misc = PERF_RECORD_MISC_USER,
87 },
88 };
89 struct hist_entry_iter iter = {
90 .hide_unresolved = false,
91 };
92
93 if (symbol_conf.cumulate_callchain)
94 iter.ops = &hist_iter_cumulative;
95 else
96 iter.ops = &hist_iter_normal;
97
98 sample.pid = fake_samples[i].pid;
99 sample.tid = fake_samples[i].pid;
100 sample.ip = fake_samples[i].ip;
101 sample.callchain = (struct ip_callchain *)fake_callchains[i];
102
103 if (perf_event__preprocess_sample(&event, machine, &al,
104 &sample) < 0)
105 goto out;
106
107 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
108 PERF_MAX_STACK_DEPTH, NULL) < 0)
109 goto out;
110
111 fake_samples[i].thread = al.thread;
112 fake_samples[i].map = al.map;
113 fake_samples[i].sym = al.sym;
114 }
115
116 return TEST_OK;
117
118out:
119 pr_debug("Not enough memory for adding a hist entry\n");
120 return TEST_FAIL;
121}
122
123static void del_hist_entries(struct hists *hists)
124{
125 struct hist_entry *he;
126 struct rb_root *root_in;
127 struct rb_root *root_out;
128 struct rb_node *node;
129
130 if (sort__need_collapse)
131 root_in = &hists->entries_collapsed;
132 else
133 root_in = hists->entries_in;
134
135 root_out = &hists->entries;
136
137 while (!RB_EMPTY_ROOT(root_out)) {
138 node = rb_first(root_out);
139
140 he = rb_entry(node, struct hist_entry, rb_node);
141 rb_erase(node, root_out);
142 rb_erase(&he->rb_node_in, root_in);
143 hist_entry__free(he);
144 }
145}
146
147typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
148
149#define COMM(he) (thread__comm_str(he->thread))
150#define DSO(he) (he->ms.map->dso->short_name)
151#define SYM(he) (he->ms.sym->name)
152#define CPU(he) (he->cpu)
153#define PID(he) (he->thread->tid)
154#define DEPTH(he) (he->callchain->max_depth)
155#define CDSO(cl) (cl->ms.map->dso->short_name)
156#define CSYM(cl) (cl->ms.sym->name)
157
158struct result {
159 u64 children;
160 u64 self;
161 const char *comm;
162 const char *dso;
163 const char *sym;
164};
165
166struct callchain_result {
167 u64 nr;
168 struct {
169 const char *dso;
170 const char *sym;
171 } node[10];
172};
173
174static int do_test(struct hists *hists, struct result *expected, size_t nr_expected,
175 struct callchain_result *expected_callchain, size_t nr_callchain)
176{
177 char buf[32];
178 size_t i, c;
179 struct hist_entry *he;
180 struct rb_root *root;
181 struct rb_node *node;
182 struct callchain_node *cnode;
183 struct callchain_list *clist;
184
185 /*
186 * adding and deleting hist entries must be done outside of this
187 * function since TEST_ASSERT_VAL() returns in case of failure.
188 */
189 hists__collapse_resort(hists, NULL);
190 hists__output_resort(hists);
191
192 if (verbose > 2) {
193 pr_info("use callchain: %d, cumulate callchain: %d\n",
194 symbol_conf.use_callchain,
195 symbol_conf.cumulate_callchain);
196 print_hists_out(hists);
197 }
198
199 root = &hists->entries;
200 for (node = rb_first(root), i = 0;
201 node && (he = rb_entry(node, struct hist_entry, rb_node));
202 node = rb_next(node), i++) {
203 scnprintf(buf, sizeof(buf), "Invalid hist entry #%zd", i);
204
205 TEST_ASSERT_VAL("Incorrect number of hist entry",
206 i < nr_expected);
207 TEST_ASSERT_VAL(buf, he->stat.period == expected[i].self &&
208 !strcmp(COMM(he), expected[i].comm) &&
209 !strcmp(DSO(he), expected[i].dso) &&
210 !strcmp(SYM(he), expected[i].sym));
211
212 if (symbol_conf.cumulate_callchain)
213 TEST_ASSERT_VAL(buf, he->stat_acc->period == expected[i].children);
214
215 if (!symbol_conf.use_callchain)
216 continue;
217
218 /* check callchain entries */
219 root = &he->callchain->node.rb_root;
220 cnode = rb_entry(rb_first(root), struct callchain_node, rb_node);
221
222 c = 0;
223 list_for_each_entry(clist, &cnode->val, list) {
224 scnprintf(buf, sizeof(buf), "Invalid callchain entry #%zd/%zd", i, c);
225
226 TEST_ASSERT_VAL("Incorrect number of callchain entry",
227 c < expected_callchain[i].nr);
228 TEST_ASSERT_VAL(buf,
229 !strcmp(CDSO(clist), expected_callchain[i].node[c].dso) &&
230 !strcmp(CSYM(clist), expected_callchain[i].node[c].sym));
231 c++;
232 }
233 /* TODO: handle multiple child nodes properly */
234 TEST_ASSERT_VAL("Incorrect number of callchain entry",
235 c <= expected_callchain[i].nr);
236 }
237 TEST_ASSERT_VAL("Incorrect number of hist entry",
238 i == nr_expected);
239 TEST_ASSERT_VAL("Incorrect number of callchain entry",
240 !symbol_conf.use_callchain || nr_expected == nr_callchain);
241 return 0;
242}
243
244/* NO callchain + NO children */
245static int test1(struct perf_evsel *evsel, struct machine *machine)
246{
247 int err;
248 struct hists *hists = &evsel->hists;
249 /*
250 * expected output:
251 *
252 * Overhead Command Shared Object Symbol
253 * ======== ======= ============= ==============
254 * 20.00% perf perf [.] main
255 * 10.00% bash [kernel] [k] page_fault
256 * 10.00% bash bash [.] main
257 * 10.00% bash bash [.] xmalloc
258 * 10.00% perf [kernel] [k] page_fault
259 * 10.00% perf [kernel] [k] schedule
260 * 10.00% perf libc [.] free
261 * 10.00% perf libc [.] malloc
262 * 10.00% perf perf [.] cmd_record
263 */
264 struct result expected[] = {
265 { 0, 2000, "perf", "perf", "main" },
266 { 0, 1000, "bash", "[kernel]", "page_fault" },
267 { 0, 1000, "bash", "bash", "main" },
268 { 0, 1000, "bash", "bash", "xmalloc" },
269 { 0, 1000, "perf", "[kernel]", "page_fault" },
270 { 0, 1000, "perf", "[kernel]", "schedule" },
271 { 0, 1000, "perf", "libc", "free" },
272 { 0, 1000, "perf", "libc", "malloc" },
273 { 0, 1000, "perf", "perf", "cmd_record" },
274 };
275
276 symbol_conf.use_callchain = false;
277 symbol_conf.cumulate_callchain = false;
278
279 setup_sorting();
280 callchain_register_param(&callchain_param);
281
282 err = add_hist_entries(hists, machine);
283 if (err < 0)
284 goto out;
285
286 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
287
288out:
289 del_hist_entries(hists);
290 reset_output_field();
291 return err;
292}
293
294/* callcain + NO children */
295static int test2(struct perf_evsel *evsel, struct machine *machine)
296{
297 int err;
298 struct hists *hists = &evsel->hists;
299 /*
300 * expected output:
301 *
302 * Overhead Command Shared Object Symbol
303 * ======== ======= ============= ==============
304 * 20.00% perf perf [.] main
305 * |
306 * --- main
307 *
308 * 10.00% bash [kernel] [k] page_fault
309 * |
310 * --- page_fault
311 * malloc
312 * main
313 *
314 * 10.00% bash bash [.] main
315 * |
316 * --- main
317 *
318 * 10.00% bash bash [.] xmalloc
319 * |
320 * --- xmalloc
321 * malloc
322 * xmalloc <--- NOTE: there's a cycle
323 * malloc
324 * xmalloc
325 * main
326 *
327 * 10.00% perf [kernel] [k] page_fault
328 * |
329 * --- page_fault
330 * sys_perf_event_open
331 * run_command
332 * main
333 *
334 * 10.00% perf [kernel] [k] schedule
335 * |
336 * --- schedule
337 * run_command
338 * main
339 *
340 * 10.00% perf libc [.] free
341 * |
342 * --- free
343 * cmd_record
344 * run_command
345 * main
346 *
347 * 10.00% perf libc [.] malloc
348 * |
349 * --- malloc
350 * cmd_record
351 * run_command
352 * main
353 *
354 * 10.00% perf perf [.] cmd_record
355 * |
356 * --- cmd_record
357 * run_command
358 * main
359 *
360 */
361 struct result expected[] = {
362 { 0, 2000, "perf", "perf", "main" },
363 { 0, 1000, "bash", "[kernel]", "page_fault" },
364 { 0, 1000, "bash", "bash", "main" },
365 { 0, 1000, "bash", "bash", "xmalloc" },
366 { 0, 1000, "perf", "[kernel]", "page_fault" },
367 { 0, 1000, "perf", "[kernel]", "schedule" },
368 { 0, 1000, "perf", "libc", "free" },
369 { 0, 1000, "perf", "libc", "malloc" },
370 { 0, 1000, "perf", "perf", "cmd_record" },
371 };
372 struct callchain_result expected_callchain[] = {
373 {
374 1, { { "perf", "main" }, },
375 },
376 {
377 3, { { "[kernel]", "page_fault" },
378 { "libc", "malloc" },
379 { "bash", "main" }, },
380 },
381 {
382 1, { { "bash", "main" }, },
383 },
384 {
385 6, { { "bash", "xmalloc" },
386 { "libc", "malloc" },
387 { "bash", "xmalloc" },
388 { "libc", "malloc" },
389 { "bash", "xmalloc" },
390 { "bash", "main" }, },
391 },
392 {
393 4, { { "[kernel]", "page_fault" },
394 { "[kernel]", "sys_perf_event_open" },
395 { "perf", "run_command" },
396 { "perf", "main" }, },
397 },
398 {
399 3, { { "[kernel]", "schedule" },
400 { "perf", "run_command" },
401 { "perf", "main" }, },
402 },
403 {
404 4, { { "libc", "free" },
405 { "perf", "cmd_record" },
406 { "perf", "run_command" },
407 { "perf", "main" }, },
408 },
409 {
410 4, { { "libc", "malloc" },
411 { "perf", "cmd_record" },
412 { "perf", "run_command" },
413 { "perf", "main" }, },
414 },
415 {
416 3, { { "perf", "cmd_record" },
417 { "perf", "run_command" },
418 { "perf", "main" }, },
419 },
420 };
421
422 symbol_conf.use_callchain = true;
423 symbol_conf.cumulate_callchain = false;
424
425 setup_sorting();
426 callchain_register_param(&callchain_param);
427
428 err = add_hist_entries(hists, machine);
429 if (err < 0)
430 goto out;
431
432 err = do_test(hists, expected, ARRAY_SIZE(expected),
433 expected_callchain, ARRAY_SIZE(expected_callchain));
434
435out:
436 del_hist_entries(hists);
437 reset_output_field();
438 return err;
439}
440
441/* NO callchain + children */
442static int test3(struct perf_evsel *evsel, struct machine *machine)
443{
444 int err;
445 struct hists *hists = &evsel->hists;
446 /*
447 * expected output:
448 *
449 * Children Self Command Shared Object Symbol
450 * ======== ======== ======= ============= =======================
451 * 70.00% 20.00% perf perf [.] main
452 * 50.00% 0.00% perf perf [.] run_command
453 * 30.00% 10.00% bash bash [.] main
454 * 30.00% 10.00% perf perf [.] cmd_record
455 * 20.00% 0.00% bash libc [.] malloc
456 * 10.00% 10.00% bash [kernel] [k] page_fault
457 * 10.00% 10.00% perf [kernel] [k] schedule
458 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
459 * 10.00% 10.00% perf [kernel] [k] page_fault
460 * 10.00% 10.00% perf libc [.] free
461 * 10.00% 10.00% perf libc [.] malloc
462 * 10.00% 10.00% bash bash [.] xmalloc
463 */
464 struct result expected[] = {
465 { 7000, 2000, "perf", "perf", "main" },
466 { 5000, 0, "perf", "perf", "run_command" },
467 { 3000, 1000, "bash", "bash", "main" },
468 { 3000, 1000, "perf", "perf", "cmd_record" },
469 { 2000, 0, "bash", "libc", "malloc" },
470 { 1000, 1000, "bash", "[kernel]", "page_fault" },
471 { 1000, 1000, "perf", "[kernel]", "schedule" },
472 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
473 { 1000, 1000, "perf", "[kernel]", "page_fault" },
474 { 1000, 1000, "perf", "libc", "free" },
475 { 1000, 1000, "perf", "libc", "malloc" },
476 { 1000, 1000, "bash", "bash", "xmalloc" },
477 };
478
479 symbol_conf.use_callchain = false;
480 symbol_conf.cumulate_callchain = true;
481
482 setup_sorting();
483 callchain_register_param(&callchain_param);
484
485 err = add_hist_entries(hists, machine);
486 if (err < 0)
487 goto out;
488
489 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
490
491out:
492 del_hist_entries(hists);
493 reset_output_field();
494 return err;
495}
496
497/* callchain + children */
498static int test4(struct perf_evsel *evsel, struct machine *machine)
499{
500 int err;
501 struct hists *hists = &evsel->hists;
502 /*
503 * expected output:
504 *
505 * Children Self Command Shared Object Symbol
506 * ======== ======== ======= ============= =======================
507 * 70.00% 20.00% perf perf [.] main
508 * |
509 * --- main
510 *
511 * 50.00% 0.00% perf perf [.] run_command
512 * |
513 * --- run_command
514 * main
515 *
516 * 30.00% 10.00% bash bash [.] main
517 * |
518 * --- main
519 *
520 * 30.00% 10.00% perf perf [.] cmd_record
521 * |
522 * --- cmd_record
523 * run_command
524 * main
525 *
526 * 20.00% 0.00% bash libc [.] malloc
527 * |
528 * --- malloc
529 * |
530 * |--50.00%-- xmalloc
531 * | main
532 * --50.00%-- main
533 *
534 * 10.00% 10.00% bash [kernel] [k] page_fault
535 * |
536 * --- page_fault
537 * malloc
538 * main
539 *
540 * 10.00% 10.00% perf [kernel] [k] schedule
541 * |
542 * --- schedule
543 * run_command
544 * main
545 *
546 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
547 * |
548 * --- sys_perf_event_open
549 * run_command
550 * main
551 *
552 * 10.00% 10.00% perf [kernel] [k] page_fault
553 * |
554 * --- page_fault
555 * sys_perf_event_open
556 * run_command
557 * main
558 *
559 * 10.00% 10.00% perf libc [.] free
560 * |
561 * --- free
562 * cmd_record
563 * run_command
564 * main
565 *
566 * 10.00% 10.00% perf libc [.] malloc
567 * |
568 * --- malloc
569 * cmd_record
570 * run_command
571 * main
572 *
573 * 10.00% 10.00% bash bash [.] xmalloc
574 * |
575 * --- xmalloc
576 * malloc
577 * xmalloc <--- NOTE: there's a cycle
578 * malloc
579 * xmalloc
580 * main
581 *
582 */
583 struct result expected[] = {
584 { 7000, 2000, "perf", "perf", "main" },
585 { 5000, 0, "perf", "perf", "run_command" },
586 { 3000, 1000, "bash", "bash", "main" },
587 { 3000, 1000, "perf", "perf", "cmd_record" },
588 { 2000, 0, "bash", "libc", "malloc" },
589 { 1000, 1000, "bash", "[kernel]", "page_fault" },
590 { 1000, 1000, "perf", "[kernel]", "schedule" },
591 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
592 { 1000, 1000, "perf", "[kernel]", "page_fault" },
593 { 1000, 1000, "perf", "libc", "free" },
594 { 1000, 1000, "perf", "libc", "malloc" },
595 { 1000, 1000, "bash", "bash", "xmalloc" },
596 };
597 struct callchain_result expected_callchain[] = {
598 {
599 1, { { "perf", "main" }, },
600 },
601 {
602 2, { { "perf", "run_command" },
603 { "perf", "main" }, },
604 },
605 {
606 1, { { "bash", "main" }, },
607 },
608 {
609 3, { { "perf", "cmd_record" },
610 { "perf", "run_command" },
611 { "perf", "main" }, },
612 },
613 {
614 4, { { "libc", "malloc" },
615 { "bash", "xmalloc" },
616 { "bash", "main" },
617 { "bash", "main" }, },
618 },
619 {
620 3, { { "[kernel]", "page_fault" },
621 { "libc", "malloc" },
622 { "bash", "main" }, },
623 },
624 {
625 3, { { "[kernel]", "schedule" },
626 { "perf", "run_command" },
627 { "perf", "main" }, },
628 },
629 {
630 3, { { "[kernel]", "sys_perf_event_open" },
631 { "perf", "run_command" },
632 { "perf", "main" }, },
633 },
634 {
635 4, { { "[kernel]", "page_fault" },
636 { "[kernel]", "sys_perf_event_open" },
637 { "perf", "run_command" },
638 { "perf", "main" }, },
639 },
640 {
641 4, { { "libc", "free" },
642 { "perf", "cmd_record" },
643 { "perf", "run_command" },
644 { "perf", "main" }, },
645 },
646 {
647 4, { { "libc", "malloc" },
648 { "perf", "cmd_record" },
649 { "perf", "run_command" },
650 { "perf", "main" }, },
651 },
652 {
653 6, { { "bash", "xmalloc" },
654 { "libc", "malloc" },
655 { "bash", "xmalloc" },
656 { "libc", "malloc" },
657 { "bash", "xmalloc" },
658 { "bash", "main" }, },
659 },
660 };
661
662 symbol_conf.use_callchain = true;
663 symbol_conf.cumulate_callchain = true;
664
665 setup_sorting();
666 callchain_register_param(&callchain_param);
667
668 err = add_hist_entries(hists, machine);
669 if (err < 0)
670 goto out;
671
672 err = do_test(hists, expected, ARRAY_SIZE(expected),
673 expected_callchain, ARRAY_SIZE(expected_callchain));
674
675out:
676 del_hist_entries(hists);
677 reset_output_field();
678 return err;
679}
680
681int test__hists_cumulate(void)
682{
683 int err = TEST_FAIL;
684 struct machines machines;
685 struct machine *machine;
686 struct perf_evsel *evsel;
687 struct perf_evlist *evlist = perf_evlist__new();
688 size_t i;
689 test_fn_t testcases[] = {
690 test1,
691 test2,
692 test3,
693 test4,
694 };
695
696 TEST_ASSERT_VAL("No memory", evlist);
697
698 err = parse_events(evlist, "cpu-clock");
699 if (err)
700 goto out;
701
702 machines__init(&machines);
703
704 /* setup threads/dso/map/symbols also */
705 machine = setup_fake_machine(&machines);
706 if (!machine)
707 goto out;
708
709 if (verbose > 1)
710 machine__fprintf(machine, stderr);
711
712 evsel = perf_evlist__first(evlist);
713
714 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
715 err = testcases[i](evsel, machine);
716 if (err < 0)
717 break;
718 }
719
720out:
721 /* tear down everything */
722 perf_evlist__delete(evlist);
723 machines__exit(&machines);
724
725 return err;
726}
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index c5ba924a3581..821f581fd930 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -21,33 +21,33 @@ struct sample {
21/* For the numbers, see hists_common.c */ 21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = { 22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */ 25 /* perf [perf] main() */
26 { .pid = 100, .ip = 0x40000 + 700, }, 26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [libc] malloc() */ 27 /* perf [libc] malloc() */
28 { .pid = 100, .ip = 0x50000 + 700, }, 28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
29 /* perf [perf] main() */ 29 /* perf [perf] main() */
30 { .pid = 200, .ip = 0x40000 + 700, }, /* will be merged */ 30 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, /* will be merged */
31 /* perf [perf] cmd_record() */ 31 /* perf [perf] cmd_record() */
32 { .pid = 200, .ip = 0x40000 + 900, }, 32 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
33 /* perf [kernel] page_fault() */ 33 /* perf [kernel] page_fault() */
34 { .pid = 200, .ip = 0xf0000 + 800, }, 34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
35 /* bash [bash] main() */ 35 /* bash [bash] main() */
36 { .pid = 300, .ip = 0x40000 + 700, }, 36 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
37 /* bash [bash] xmalloc() */ 37 /* bash [bash] xmalloc() */
38 { .pid = 300, .ip = 0x40000 + 800, }, 38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
39 /* bash [libc] malloc() */ 39 /* bash [libc] malloc() */
40 { .pid = 300, .ip = 0x50000 + 700, }, 40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
41 /* bash [kernel] page_fault() */ 41 /* bash [kernel] page_fault() */
42 { .pid = 300, .ip = 0xf0000 + 800, }, 42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43}; 43};
44 44
45static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) 45static int add_hist_entries(struct perf_evlist *evlist,
46 struct machine *machine __maybe_unused)
46{ 47{
47 struct perf_evsel *evsel; 48 struct perf_evsel *evsel;
48 struct addr_location al; 49 struct addr_location al;
49 struct hist_entry *he; 50 struct perf_sample sample = { .period = 100, };
50 struct perf_sample sample = { .cpu = 0, };
51 size_t i; 51 size_t i;
52 52
53 /* 53 /*
@@ -62,6 +62,10 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
62 .misc = PERF_RECORD_MISC_USER, 62 .misc = PERF_RECORD_MISC_USER,
63 }, 63 },
64 }; 64 };
65 struct hist_entry_iter iter = {
66 .ops = &hist_iter_normal,
67 .hide_unresolved = false,
68 };
65 69
66 /* make sure it has no filter at first */ 70 /* make sure it has no filter at first */
67 evsel->hists.thread_filter = NULL; 71 evsel->hists.thread_filter = NULL;
@@ -76,18 +80,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
76 &sample) < 0) 80 &sample) < 0)
77 goto out; 81 goto out;
78 82
79 he = __hists__add_entry(&evsel->hists, &al, NULL, 83 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
80 NULL, NULL, 100, 1, 0); 84 PERF_MAX_STACK_DEPTH, NULL) < 0)
81 if (he == NULL)
82 goto out; 85 goto out;
83 86
84 fake_samples[i].thread = al.thread; 87 fake_samples[i].thread = al.thread;
85 fake_samples[i].map = al.map; 88 fake_samples[i].map = al.map;
86 fake_samples[i].sym = al.sym; 89 fake_samples[i].sym = al.sym;
87
88 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
89 if (!he->filtered)
90 he->hists->stats.nr_non_filtered_samples++;
91 } 90 }
92 } 91 }
93 92
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 5ffa2c3eb77d..d4b34b0f50a2 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -21,41 +21,41 @@ struct sample {
21/* For the numbers, see hists_common.c */ 21/* For the numbers, see hists_common.c */
22static struct sample fake_common_samples[] = { 22static struct sample fake_common_samples[] = {
23 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */ 25 /* perf [perf] main() */
26 { .pid = 200, .ip = 0x40000 + 700, }, 26 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [perf] cmd_record() */ 27 /* perf [perf] cmd_record() */
28 { .pid = 200, .ip = 0x40000 + 900, }, 28 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
29 /* bash [bash] xmalloc() */ 29 /* bash [bash] xmalloc() */
30 { .pid = 300, .ip = 0x40000 + 800, }, 30 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
31 /* bash [libc] malloc() */ 31 /* bash [libc] malloc() */
32 { .pid = 300, .ip = 0x50000 + 700, }, 32 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
33}; 33};
34 34
35static struct sample fake_samples[][5] = { 35static struct sample fake_samples[][5] = {
36 { 36 {
37 /* perf [perf] run_command() */ 37 /* perf [perf] run_command() */
38 { .pid = 100, .ip = 0x40000 + 800, }, 38 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, },
39 /* perf [libc] malloc() */ 39 /* perf [libc] malloc() */
40 { .pid = 100, .ip = 0x50000 + 700, }, 40 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
41 /* perf [kernel] page_fault() */ 41 /* perf [kernel] page_fault() */
42 { .pid = 100, .ip = 0xf0000 + 800, }, 42 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43 /* perf [kernel] sys_perf_event_open() */ 43 /* perf [kernel] sys_perf_event_open() */
44 { .pid = 200, .ip = 0xf0000 + 900, }, 44 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, },
45 /* bash [libc] free() */ 45 /* bash [libc] free() */
46 { .pid = 300, .ip = 0x50000 + 800, }, 46 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_FREE, },
47 }, 47 },
48 { 48 {
49 /* perf [libc] free() */ 49 /* perf [libc] free() */
50 { .pid = 200, .ip = 0x50000 + 800, }, 50 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, },
51 /* bash [libc] malloc() */ 51 /* bash [libc] malloc() */
52 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ 52 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */
53 /* bash [bash] xfee() */ 53 /* bash [bash] xfee() */
54 { .pid = 300, .ip = 0x40000 + 900, }, 54 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XFREE, },
55 /* bash [libc] realloc() */ 55 /* bash [libc] realloc() */
56 { .pid = 300, .ip = 0x50000 + 900, }, 56 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_REALLOC, },
57 /* bash [kernel] page_fault() */ 57 /* bash [kernel] page_fault() */
58 { .pid = 300, .ip = 0xf0000 + 800, }, 58 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
59 }, 59 },
60}; 60};
61 61
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
64 struct perf_evsel *evsel; 64 struct perf_evsel *evsel;
65 struct addr_location al; 65 struct addr_location al;
66 struct hist_entry *he; 66 struct hist_entry *he;
67 struct perf_sample sample = { .cpu = 0, }; 67 struct perf_sample sample = { .period = 1, };
68 size_t i = 0, k; 68 size_t i = 0, k;
69 69
70 /* 70 /*
@@ -88,7 +88,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
88 goto out; 88 goto out;
89 89
90 he = __hists__add_entry(&evsel->hists, &al, NULL, 90 he = __hists__add_entry(&evsel->hists, &al, NULL,
91 NULL, NULL, 1, 1, 0); 91 NULL, NULL, 1, 1, 0, true);
92 if (he == NULL) 92 if (he == NULL)
93 goto out; 93 goto out;
94 94
@@ -112,7 +112,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
112 goto out; 112 goto out;
113 113
114 he = __hists__add_entry(&evsel->hists, &al, NULL, 114 he = __hists__add_entry(&evsel->hists, &al, NULL,
115 NULL, NULL, 1, 1, 0); 115 NULL, NULL, 1, 1, 0, true);
116 if (he == NULL) 116 if (he == NULL)
117 goto out; 117 goto out;
118 118
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index a16850551797..e3bbd6c54c1b 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -22,31 +22,31 @@ struct sample {
22/* For the numbers, see hists_common.c */ 22/* For the numbers, see hists_common.c */
23static struct sample fake_samples[] = { 23static struct sample fake_samples[] = {
24 /* perf [kernel] schedule() */ 24 /* perf [kernel] schedule() */
25 { .cpu = 0, .pid = 100, .ip = 0xf0000 + 700, }, 25 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
26 /* perf [perf] main() */ 26 /* perf [perf] main() */
27 { .cpu = 1, .pid = 100, .ip = 0x40000 + 700, }, 27 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
28 /* perf [perf] cmd_record() */ 28 /* perf [perf] cmd_record() */
29 { .cpu = 1, .pid = 100, .ip = 0x40000 + 900, }, 29 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
30 /* perf [libc] malloc() */ 30 /* perf [libc] malloc() */
31 { .cpu = 1, .pid = 100, .ip = 0x50000 + 700, }, 31 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
32 /* perf [libc] free() */ 32 /* perf [libc] free() */
33 { .cpu = 2, .pid = 100, .ip = 0x50000 + 800, }, 33 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
34 /* perf [perf] main() */ 34 /* perf [perf] main() */
35 { .cpu = 2, .pid = 200, .ip = 0x40000 + 700, }, 35 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
36 /* perf [kernel] page_fault() */ 36 /* perf [kernel] page_fault() */
37 { .cpu = 2, .pid = 200, .ip = 0xf0000 + 800, }, 37 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
38 /* bash [bash] main() */ 38 /* bash [bash] main() */
39 { .cpu = 3, .pid = 300, .ip = 0x40000 + 700, }, 39 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
40 /* bash [bash] xmalloc() */ 40 /* bash [bash] xmalloc() */
41 { .cpu = 0, .pid = 300, .ip = 0x40000 + 800, }, 41 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
42 /* bash [kernel] page_fault() */ 42 /* bash [kernel] page_fault() */
43 { .cpu = 1, .pid = 300, .ip = 0xf0000 + 800, }, 43 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
44}; 44};
45 45
46static int add_hist_entries(struct hists *hists, struct machine *machine) 46static int add_hist_entries(struct hists *hists, struct machine *machine)
47{ 47{
48 struct addr_location al; 48 struct addr_location al;
49 struct hist_entry *he; 49 struct perf_evsel *evsel = hists_to_evsel(hists);
50 struct perf_sample sample = { .period = 100, }; 50 struct perf_sample sample = { .period = 100, };
51 size_t i; 51 size_t i;
52 52
@@ -56,6 +56,10 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
56 .misc = PERF_RECORD_MISC_USER, 56 .misc = PERF_RECORD_MISC_USER,
57 }, 57 },
58 }; 58 };
59 struct hist_entry_iter iter = {
60 .ops = &hist_iter_normal,
61 .hide_unresolved = false,
62 };
59 63
60 sample.cpu = fake_samples[i].cpu; 64 sample.cpu = fake_samples[i].cpu;
61 sample.pid = fake_samples[i].pid; 65 sample.pid = fake_samples[i].pid;
@@ -66,9 +70,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
66 &sample) < 0) 70 &sample) < 0)
67 goto out; 71 goto out;
68 72
69 he = __hists__add_entry(hists, &al, NULL, NULL, NULL, 73 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
70 sample.period, 1, 0); 74 PERF_MAX_STACK_DEPTH, NULL) < 0)
71 if (he == NULL)
72 goto out; 75 goto out;
73 76
74 fake_samples[i].thread = al.thread; 77 fake_samples[i].thread = al.thread;
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2f92d6e7ee00..69a71ff84e01 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -205,8 +205,7 @@ $(run):
205 ( eval $$cmd ) >> $@ 2>&1; \ 205 ( eval $$cmd ) >> $@ 2>&1; \
206 echo " test: $(call test,$@)" >> $@ 2>&1; \ 206 echo " test: $(call test,$@)" >> $@ 2>&1; \
207 $(call test,$@) && \ 207 $(call test,$@) && \
208 rm -f $@ \ 208 rm -rf $@ $$TMP_DEST || (cat $@ ; false)
209 rm -rf $$TMP_DEST
210 209
211$(run_O): 210$(run_O):
212 $(call clean) 211 $(call clean)
@@ -217,9 +216,7 @@ $(run_O):
217 ( eval $$cmd ) >> $@ 2>&1 && \ 216 ( eval $$cmd ) >> $@ 2>&1 && \
218 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 217 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
219 $(call test_O,$@) && \ 218 $(call test_O,$@) && \
220 rm -f $@ && \ 219 rm -rf $@ $$TMP_O $$TMP_DEST || (cat $@ ; false)
221 rm -rf $$TMP_O \
222 rm -rf $$TMP_DEST
223 220
224tarpkg: 221tarpkg:
225 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ 222 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index d76c0e2e6635..ed64790a395f 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -28,6 +28,8 @@ int test__syscall_open_tp_fields(void);
28int test__pmu(void); 28int test__pmu(void);
29int test__attr(void); 29int test__attr(void);
30int test__dso_data(void); 30int test__dso_data(void);
31int test__dso_data_cache(void);
32int test__dso_data_reopen(void);
31int test__parse_events(void); 33int test__parse_events(void);
32int test__hists_link(void); 34int test__hists_link(void);
33int test__python_use(void); 35int test__python_use(void);
@@ -45,6 +47,7 @@ int test__hists_filter(void);
45int test__mmap_thread_lookup(void); 47int test__mmap_thread_lookup(void);
46int test__thread_mg_share(void); 48int test__thread_mg_share(void);
47int test__hists_output(void); 49int test__hists_output(void);
50int test__hists_cumulate(void);
48 51
49#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) 52#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
50#ifdef HAVE_DWARF_UNWIND_SUPPORT 53#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index d11541d4d7d7..3ccf6e14f89b 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -194,7 +194,7 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
194 ui_helpline__vpush(format, args); 194 ui_helpline__vpush(format, args);
195 va_end(args); 195 va_end(args);
196 } else { 196 } else {
197 while ((key == ui__question_window("Warning!", text, 197 while ((key = ui__question_window("Warning!", text,
198 "Press any key...", 198 "Press any key...",
199 timeout)) == K_RESIZE) 199 timeout)) == K_RESIZE)
200 ui_browser__handle_resize(browser); 200 ui_browser__handle_resize(browser);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 1c331b934ffc..52c03fbbba17 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -37,7 +37,6 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
37static void hist_browser__update_nr_entries(struct hist_browser *hb); 37static void hist_browser__update_nr_entries(struct hist_browser *hb);
38 38
39static struct rb_node *hists__filter_entries(struct rb_node *nd, 39static struct rb_node *hists__filter_entries(struct rb_node *nd,
40 struct hists *hists,
41 float min_pcnt); 40 float min_pcnt);
42 41
43static bool hist_browser__has_filter(struct hist_browser *hb) 42static bool hist_browser__has_filter(struct hist_browser *hb)
@@ -319,7 +318,7 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
319 struct hists *hists = browser->hists; 318 struct hists *hists = browser->hists;
320 319
321 for (nd = rb_first(&hists->entries); 320 for (nd = rb_first(&hists->entries);
322 (nd = hists__filter_entries(nd, hists, browser->min_pcnt)) != NULL; 321 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
323 nd = rb_next(nd)) { 322 nd = rb_next(nd)) {
324 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 323 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
325 hist_entry__set_folding(he, unfold); 324 hist_entry__set_folding(he, unfold);
@@ -651,13 +650,36 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
651 __hpp__slsmg_color_printf, true); \ 650 __hpp__slsmg_color_printf, true); \
652} 651}
653 652
653#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
654static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
655{ \
656 return he->stat_acc->_field; \
657} \
658 \
659static int \
660hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
661 struct perf_hpp *hpp, \
662 struct hist_entry *he) \
663{ \
664 if (!symbol_conf.cumulate_callchain) { \
665 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
666 slsmg_printf("%s", hpp->buf); \
667 \
668 return ret; \
669 } \
670 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
671 __hpp__slsmg_color_printf, true); \
672}
673
654__HPP_COLOR_PERCENT_FN(overhead, period) 674__HPP_COLOR_PERCENT_FN(overhead, period)
655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 675__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
656__HPP_COLOR_PERCENT_FN(overhead_us, period_us) 676__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 677__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 678__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
679__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
659 680
660#undef __HPP_COLOR_PERCENT_FN 681#undef __HPP_COLOR_PERCENT_FN
682#undef __HPP_COLOR_ACC_PERCENT_FN
661 683
662void hist_browser__init_hpp(void) 684void hist_browser__init_hpp(void)
663{ 685{
@@ -671,6 +693,8 @@ void hist_browser__init_hpp(void)
671 hist_browser__hpp_color_overhead_guest_sys; 693 hist_browser__hpp_color_overhead_guest_sys;
672 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 694 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
673 hist_browser__hpp_color_overhead_guest_us; 695 hist_browser__hpp_color_overhead_guest_us;
696 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
697 hist_browser__hpp_color_overhead_acc;
674} 698}
675 699
676static int hist_browser__show_entry(struct hist_browser *browser, 700static int hist_browser__show_entry(struct hist_browser *browser,
@@ -783,15 +807,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
783 807
784 for (nd = browser->top; nd; nd = rb_next(nd)) { 808 for (nd = browser->top; nd; nd = rb_next(nd)) {
785 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 809 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
786 u64 total = hists__total_period(h->hists); 810 float percent;
787 float percent = 0.0;
788 811
789 if (h->filtered) 812 if (h->filtered)
790 continue; 813 continue;
791 814
792 if (total) 815 percent = hist_entry__get_percent_limit(h);
793 percent = h->stat.period * 100.0 / total;
794
795 if (percent < hb->min_pcnt) 816 if (percent < hb->min_pcnt)
796 continue; 817 continue;
797 818
@@ -804,16 +825,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
804} 825}
805 826
806static struct rb_node *hists__filter_entries(struct rb_node *nd, 827static struct rb_node *hists__filter_entries(struct rb_node *nd,
807 struct hists *hists,
808 float min_pcnt) 828 float min_pcnt)
809{ 829{
810 while (nd != NULL) { 830 while (nd != NULL) {
811 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 831 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
812 u64 total = hists__total_period(hists); 832 float percent = hist_entry__get_percent_limit(h);
813 float percent = 0.0;
814
815 if (total)
816 percent = h->stat.period * 100.0 / total;
817 833
818 if (!h->filtered && percent >= min_pcnt) 834 if (!h->filtered && percent >= min_pcnt)
819 return nd; 835 return nd;
@@ -825,16 +841,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
825} 841}
826 842
827static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 843static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
828 struct hists *hists,
829 float min_pcnt) 844 float min_pcnt)
830{ 845{
831 while (nd != NULL) { 846 while (nd != NULL) {
832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 847 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
833 u64 total = hists__total_period(hists); 848 float percent = hist_entry__get_percent_limit(h);
834 float percent = 0.0;
835
836 if (total)
837 percent = h->stat.period * 100.0 / total;
838 849
839 if (!h->filtered && percent >= min_pcnt) 850 if (!h->filtered && percent >= min_pcnt)
840 return nd; 851 return nd;
@@ -863,14 +874,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
863 switch (whence) { 874 switch (whence) {
864 case SEEK_SET: 875 case SEEK_SET:
865 nd = hists__filter_entries(rb_first(browser->entries), 876 nd = hists__filter_entries(rb_first(browser->entries),
866 hb->hists, hb->min_pcnt); 877 hb->min_pcnt);
867 break; 878 break;
868 case SEEK_CUR: 879 case SEEK_CUR:
869 nd = browser->top; 880 nd = browser->top;
870 goto do_offset; 881 goto do_offset;
871 case SEEK_END: 882 case SEEK_END:
872 nd = hists__filter_prev_entries(rb_last(browser->entries), 883 nd = hists__filter_prev_entries(rb_last(browser->entries),
873 hb->hists, hb->min_pcnt); 884 hb->min_pcnt);
874 first = false; 885 first = false;
875 break; 886 break;
876 default: 887 default:
@@ -913,8 +924,7 @@ do_offset:
913 break; 924 break;
914 } 925 }
915 } 926 }
916 nd = hists__filter_entries(rb_next(nd), hb->hists, 927 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
917 hb->min_pcnt);
918 if (nd == NULL) 928 if (nd == NULL)
919 break; 929 break;
920 --offset; 930 --offset;
@@ -947,7 +957,7 @@ do_offset:
947 } 957 }
948 } 958 }
949 959
950 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, 960 nd = hists__filter_prev_entries(rb_prev(nd),
951 hb->min_pcnt); 961 hb->min_pcnt);
952 if (nd == NULL) 962 if (nd == NULL)
953 break; 963 break;
@@ -1126,7 +1136,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1126static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1136static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1127{ 1137{
1128 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1138 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1129 browser->hists,
1130 browser->min_pcnt); 1139 browser->min_pcnt);
1131 int printed = 0; 1140 int printed = 0;
1132 1141
@@ -1134,8 +1143,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1134 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1143 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1135 1144
1136 printed += hist_browser__fprintf_entry(browser, h, fp); 1145 printed += hist_browser__fprintf_entry(browser, h, fp);
1137 nd = hists__filter_entries(rb_next(nd), browser->hists, 1146 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
1138 browser->min_pcnt);
1139 } 1147 }
1140 1148
1141 return printed; 1149 return printed;
@@ -1372,8 +1380,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1372 return; 1380 return;
1373 } 1381 }
1374 1382
1375 while ((nd = hists__filter_entries(nd, hb->hists, 1383 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1376 hb->min_pcnt)) != NULL) {
1377 nr_entries++; 1384 nr_entries++;
1378 nd = rb_next(nd); 1385 nd = rb_next(nd);
1379 } 1386 }
@@ -1699,14 +1706,14 @@ zoom_dso:
1699zoom_out_dso: 1706zoom_out_dso:
1700 ui_helpline__pop(); 1707 ui_helpline__pop();
1701 browser->hists->dso_filter = NULL; 1708 browser->hists->dso_filter = NULL;
1702 sort_dso.elide = false; 1709 perf_hpp__set_elide(HISTC_DSO, false);
1703 } else { 1710 } else {
1704 if (dso == NULL) 1711 if (dso == NULL)
1705 continue; 1712 continue;
1706 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1713 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1707 dso->kernel ? "the Kernel" : dso->short_name); 1714 dso->kernel ? "the Kernel" : dso->short_name);
1708 browser->hists->dso_filter = dso; 1715 browser->hists->dso_filter = dso;
1709 sort_dso.elide = true; 1716 perf_hpp__set_elide(HISTC_DSO, true);
1710 pstack__push(fstack, &browser->hists->dso_filter); 1717 pstack__push(fstack, &browser->hists->dso_filter);
1711 } 1718 }
1712 hists__filter_by_dso(hists); 1719 hists__filter_by_dso(hists);
@@ -1718,13 +1725,13 @@ zoom_thread:
1718zoom_out_thread: 1725zoom_out_thread:
1719 ui_helpline__pop(); 1726 ui_helpline__pop();
1720 browser->hists->thread_filter = NULL; 1727 browser->hists->thread_filter = NULL;
1721 sort_thread.elide = false; 1728 perf_hpp__set_elide(HISTC_THREAD, false);
1722 } else { 1729 } else {
1723 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1730 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1724 thread->comm_set ? thread__comm_str(thread) : "", 1731 thread->comm_set ? thread__comm_str(thread) : "",
1725 thread->tid); 1732 thread->tid);
1726 browser->hists->thread_filter = thread; 1733 browser->hists->thread_filter = thread;
1727 sort_thread.elide = true; 1734 perf_hpp__set_elide(HISTC_THREAD, false);
1728 pstack__push(fstack, &browser->hists->thread_filter); 1735 pstack__push(fstack, &browser->hists->thread_filter);
1729 } 1736 }
1730 hists__filter_by_thread(hists); 1737 hists__filter_by_thread(hists);
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 9d90683914d4..6ca60e482cdc 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -47,11 +47,26 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
47 __percent_color_snprintf, true); \ 47 __percent_color_snprintf, true); \
48} 48}
49 49
50#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
51static u64 he_get_acc_##_field(struct hist_entry *he) \
52{ \
53 return he->stat_acc->_field; \
54} \
55 \
56static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
57 struct perf_hpp *hpp, \
58 struct hist_entry *he) \
59{ \
60 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
61 __percent_color_snprintf, true); \
62}
63
50__HPP_COLOR_PERCENT_FN(overhead, period) 64__HPP_COLOR_PERCENT_FN(overhead, period)
51__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 65__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
52__HPP_COLOR_PERCENT_FN(overhead_us, period_us) 66__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
53__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 67__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
54__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 68__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
69__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
55 70
56#undef __HPP_COLOR_PERCENT_FN 71#undef __HPP_COLOR_PERCENT_FN
57 72
@@ -68,6 +83,8 @@ void perf_gtk__init_hpp(void)
68 perf_gtk__hpp_color_overhead_guest_sys; 83 perf_gtk__hpp_color_overhead_guest_sys;
69 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 84 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
70 perf_gtk__hpp_color_overhead_guest_us; 85 perf_gtk__hpp_color_overhead_guest_us;
86 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
87 perf_gtk__hpp_color_overhead_acc;
71} 88}
72 89
73static void callchain_list__sym_name(struct callchain_list *cl, 90static void callchain_list__sym_name(struct callchain_list *cl,
@@ -181,6 +198,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
181 if (perf_hpp__should_skip(fmt)) 198 if (perf_hpp__should_skip(fmt))
182 continue; 199 continue;
183 200
201 /*
202 * XXX no way to determine where symcol column is..
203 * Just use last column for now.
204 */
205 if (perf_hpp__is_sort_entry(fmt))
206 sym_col = col_idx;
207
184 fmt->header(fmt, &hpp, hists_to_evsel(hists)); 208 fmt->header(fmt, &hpp, hists_to_evsel(hists));
185 209
186 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 210 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -209,14 +233,12 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
209 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 233 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
210 GtkTreeIter iter; 234 GtkTreeIter iter;
211 u64 total = hists__total_period(h->hists); 235 u64 total = hists__total_period(h->hists);
212 float percent = 0.0; 236 float percent;
213 237
214 if (h->filtered) 238 if (h->filtered)
215 continue; 239 continue;
216 240
217 if (total) 241 percent = hist_entry__get_percent_limit(h);
218 percent = h->stat.period * 100.0 / total;
219
220 if (percent < min_pcnt) 242 if (percent < min_pcnt)
221 continue; 243 continue;
222 244
@@ -238,7 +260,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
238 260
239 if (symbol_conf.use_callchain && sort__has_sym) { 261 if (symbol_conf.use_callchain && sort__has_sym) {
240 if (callchain_param.mode == CHAIN_GRAPH_REL) 262 if (callchain_param.mode == CHAIN_GRAPH_REL)
241 total = h->stat.period; 263 total = symbol_conf.cumulate_callchain ?
264 h->stat_acc->period : h->stat.period;
242 265
243 perf_gtk__add_callchain(&h->sorted_chain, store, &iter, 266 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
244 sym_col, total); 267 sym_col, total);
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 4484f5bd1b14..498adb23c02e 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -104,6 +104,18 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
104 return ret; 104 return ret;
105} 105}
106 106
107int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
108 hpp_field_fn get_field, const char *fmt,
109 hpp_snprint_fn print_fn, bool fmt_percent)
110{
111 if (!symbol_conf.cumulate_callchain) {
112 return snprintf(hpp->buf, hpp->size, "%*s",
113 fmt_percent ? 8 : 12, "N/A");
114 }
115
116 return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
117}
118
107static int field_cmp(u64 field_a, u64 field_b) 119static int field_cmp(u64 field_a, u64 field_b)
108{ 120{
109 if (field_a > field_b) 121 if (field_a > field_b)
@@ -160,6 +172,24 @@ out:
160 return ret; 172 return ret;
161} 173}
162 174
175static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
176 hpp_field_fn get_field)
177{
178 s64 ret = 0;
179
180 if (symbol_conf.cumulate_callchain) {
181 /*
182 * Put caller above callee when they have equal period.
183 */
184 ret = field_cmp(get_field(a), get_field(b));
185 if (ret)
186 return ret;
187
188 ret = b->callchain->max_depth - a->callchain->max_depth;
189 }
190 return ret;
191}
192
163#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 193#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
164static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 194static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
165 struct perf_hpp *hpp, \ 195 struct perf_hpp *hpp, \
@@ -242,6 +272,34 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
242 return __hpp__sort(a, b, he_get_##_field); \ 272 return __hpp__sort(a, b, he_get_##_field); \
243} 273}
244 274
275#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
276static u64 he_get_acc_##_field(struct hist_entry *he) \
277{ \
278 return he->stat_acc->_field; \
279} \
280 \
281static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
282 struct perf_hpp *hpp, struct hist_entry *he) \
283{ \
284 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
285 hpp_color_scnprintf, true); \
286}
287
288#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
289static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
290 struct perf_hpp *hpp, struct hist_entry *he) \
291{ \
292 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
293 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \
294 hpp_entry_scnprintf, true); \
295}
296
297#define __HPP_SORT_ACC_FN(_type, _field) \
298static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
299{ \
300 return __hpp__sort_acc(a, b, he_get_acc_##_field); \
301}
302
245#define __HPP_ENTRY_RAW_FN(_type, _field) \ 303#define __HPP_ENTRY_RAW_FN(_type, _field) \
246static u64 he_get_raw_##_field(struct hist_entry *he) \ 304static u64 he_get_raw_##_field(struct hist_entry *he) \
247{ \ 305{ \
@@ -270,18 +328,27 @@ __HPP_COLOR_PERCENT_FN(_type, _field) \
270__HPP_ENTRY_PERCENT_FN(_type, _field) \ 328__HPP_ENTRY_PERCENT_FN(_type, _field) \
271__HPP_SORT_FN(_type, _field) 329__HPP_SORT_FN(_type, _field)
272 330
331#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
332__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
333__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
334__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
335__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
336__HPP_SORT_ACC_FN(_type, _field)
337
273#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 338#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
274__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 339__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
275__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 340__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
276__HPP_ENTRY_RAW_FN(_type, _field) \ 341__HPP_ENTRY_RAW_FN(_type, _field) \
277__HPP_SORT_RAW_FN(_type, _field) 342__HPP_SORT_RAW_FN(_type, _field)
278 343
344__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
279 345
280HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 346HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
281HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 347HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
282HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 348HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
283HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 349HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
284HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) 350HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
351HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
285 352
286HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 353HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
287HPP_RAW_FNS(period, "Period", period, 12, 12) 354HPP_RAW_FNS(period, "Period", period, 12, 12)
@@ -303,6 +370,17 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
303 .sort = hpp__sort_ ## _name, \ 370 .sort = hpp__sort_ ## _name, \
304 } 371 }
305 372
373#define HPP__COLOR_ACC_PRINT_FNS(_name) \
374 { \
375 .header = hpp__header_ ## _name, \
376 .width = hpp__width_ ## _name, \
377 .color = hpp__color_ ## _name, \
378 .entry = hpp__entry_ ## _name, \
379 .cmp = hpp__nop_cmp, \
380 .collapse = hpp__nop_cmp, \
381 .sort = hpp__sort_ ## _name, \
382 }
383
306#define HPP__PRINT_FNS(_name) \ 384#define HPP__PRINT_FNS(_name) \
307 { \ 385 { \
308 .header = hpp__header_ ## _name, \ 386 .header = hpp__header_ ## _name, \
@@ -319,6 +397,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
319 HPP__COLOR_PRINT_FNS(overhead_us), 397 HPP__COLOR_PRINT_FNS(overhead_us),
320 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 398 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
321 HPP__COLOR_PRINT_FNS(overhead_guest_us), 399 HPP__COLOR_PRINT_FNS(overhead_guest_us),
400 HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
322 HPP__PRINT_FNS(samples), 401 HPP__PRINT_FNS(samples),
323 HPP__PRINT_FNS(period) 402 HPP__PRINT_FNS(period)
324}; 403};
@@ -328,16 +407,23 @@ LIST_HEAD(perf_hpp__sort_list);
328 407
329 408
330#undef HPP__COLOR_PRINT_FNS 409#undef HPP__COLOR_PRINT_FNS
410#undef HPP__COLOR_ACC_PRINT_FNS
331#undef HPP__PRINT_FNS 411#undef HPP__PRINT_FNS
332 412
333#undef HPP_PERCENT_FNS 413#undef HPP_PERCENT_FNS
414#undef HPP_PERCENT_ACC_FNS
334#undef HPP_RAW_FNS 415#undef HPP_RAW_FNS
335 416
336#undef __HPP_HEADER_FN 417#undef __HPP_HEADER_FN
337#undef __HPP_WIDTH_FN 418#undef __HPP_WIDTH_FN
338#undef __HPP_COLOR_PERCENT_FN 419#undef __HPP_COLOR_PERCENT_FN
339#undef __HPP_ENTRY_PERCENT_FN 420#undef __HPP_ENTRY_PERCENT_FN
421#undef __HPP_COLOR_ACC_PERCENT_FN
422#undef __HPP_ENTRY_ACC_PERCENT_FN
340#undef __HPP_ENTRY_RAW_FN 423#undef __HPP_ENTRY_RAW_FN
424#undef __HPP_SORT_FN
425#undef __HPP_SORT_ACC_FN
426#undef __HPP_SORT_RAW_FN
341 427
342 428
343void perf_hpp__init(void) 429void perf_hpp__init(void)
@@ -361,6 +447,13 @@ void perf_hpp__init(void)
361 if (field_order) 447 if (field_order)
362 return; 448 return;
363 449
450 if (symbol_conf.cumulate_callchain) {
451 perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
452
453 perf_hpp__format[PERF_HPP__OVERHEAD].header =
454 hpp__header_overhead_self;
455 }
456
364 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 457 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
365 458
366 if (symbol_conf.show_cpu_utilization) { 459 if (symbol_conf.show_cpu_utilization) {
@@ -383,6 +476,12 @@ void perf_hpp__init(void)
383 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; 476 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
384 if (list_empty(list)) 477 if (list_empty(list))
385 list_add(list, &perf_hpp__sort_list); 478 list_add(list, &perf_hpp__sort_list);
479
480 if (symbol_conf.cumulate_callchain) {
481 list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
482 if (list_empty(list))
483 list_add(list, &perf_hpp__sort_list);
484 }
386} 485}
387 486
388void perf_hpp__column_register(struct perf_hpp_fmt *format) 487void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -390,6 +489,11 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)
390 list_add_tail(&format->list, &perf_hpp__list); 489 list_add_tail(&format->list, &perf_hpp__list);
391} 490}
392 491
492void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
493{
494 list_del(&format->list);
495}
496
393void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 497void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
394{ 498{
395 list_add_tail(&format->sort_list, &perf_hpp__sort_list); 499 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
@@ -401,6 +505,21 @@ void perf_hpp__column_enable(unsigned col)
401 perf_hpp__column_register(&perf_hpp__format[col]); 505 perf_hpp__column_register(&perf_hpp__format[col]);
402} 506}
403 507
508void perf_hpp__column_disable(unsigned col)
509{
510 BUG_ON(col >= PERF_HPP__MAX_INDEX);
511 perf_hpp__column_unregister(&perf_hpp__format[col]);
512}
513
514void perf_hpp__cancel_cumulate(void)
515{
516 if (field_order)
517 return;
518
519 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
520 perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
521}
522
404void perf_hpp__setup_output_field(void) 523void perf_hpp__setup_output_field(void)
405{ 524{
406 struct perf_hpp_fmt *fmt; 525 struct perf_hpp_fmt *fmt;
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 9f57991025a9..90122abd3721 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -271,7 +271,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
271{ 271{
272 switch (callchain_param.mode) { 272 switch (callchain_param.mode) {
273 case CHAIN_GRAPH_REL: 273 case CHAIN_GRAPH_REL:
274 return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, 274 return callchain__fprintf_graph(fp, &he->sorted_chain,
275 symbol_conf.cumulate_callchain ?
276 he->stat_acc->period : he->stat.period,
275 left_margin); 277 left_margin);
276 break; 278 break;
277 case CHAIN_GRAPH_ABS: 279 case CHAIN_GRAPH_ABS:
@@ -461,12 +463,12 @@ print_entries:
461 463
462 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 464 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
463 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 465 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
464 float percent = h->stat.period * 100.0 / 466 float percent;
465 hists->stats.total_period;
466 467
467 if (h->filtered) 468 if (h->filtered)
468 continue; 469 continue;
469 470
471 percent = hist_entry__get_percent_limit(h);
470 if (percent < min_pcnt) 472 if (percent < min_pcnt)
471 continue; 473 continue;
472 474
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9a42382b3921..48b6d3f50012 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
616 if (sample->callchain == NULL) 616 if (sample->callchain == NULL)
617 return 0; 617 return 0;
618 618
619 if (symbol_conf.use_callchain || sort__has_parent) { 619 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
620 sort__has_parent) {
620 return machine__resolve_callchain(al->machine, evsel, al->thread, 621 return machine__resolve_callchain(al->machine, evsel, al->thread,
621 sample, parent, al, max_stack); 622 sample, parent, al, max_stack);
622 } 623 }
@@ -629,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
629 return 0; 630 return 0;
630 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
631} 632}
633
634int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
635 bool hide_unresolved)
636{
637 al->map = node->map;
638 al->sym = node->sym;
639 if (node->map)
640 al->addr = node->map->map_ip(node->map, node->ip);
641 else
642 al->addr = node->ip;
643
644 if (al->sym == NULL) {
645 if (hide_unresolved)
646 return 0;
647 if (al->map == NULL)
648 goto out;
649 }
650
651 if (al->map->groups == &al->machine->kmaps) {
652 if (machine__is_host(al->machine)) {
653 al->cpumode = PERF_RECORD_MISC_KERNEL;
654 al->level = 'k';
655 } else {
656 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
657 al->level = 'g';
658 }
659 } else {
660 if (machine__is_host(al->machine)) {
661 al->cpumode = PERF_RECORD_MISC_USER;
662 al->level = '.';
663 } else if (perf_guest) {
664 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
665 al->level = 'u';
666 } else {
667 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
668 al->level = 'H';
669 }
670 }
671
672out:
673 return 1;
674}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index bde2b0cc24cf..8f84423a75da 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -162,7 +162,18 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
162 struct perf_evsel *evsel, struct addr_location *al, 162 struct perf_evsel *evsel, struct addr_location *al,
163 int max_stack); 163 int max_stack);
164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
165int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
166 bool hide_unresolved);
165 167
166extern const char record_callchain_help[]; 168extern const char record_callchain_help[];
167int parse_callchain_report_opt(const char *arg); 169int parse_callchain_report_opt(const char *arg);
170
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src)
173{
174 *dest = *src;
175
176 dest->first = src->curr;
177 dest->nr -= src->pos;
178}
168#endif /* __PERF_CALLCHAIN_H */ 179#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 64453d63b971..819f10414f08 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1,3 +1,6 @@
1#include <asm/bug.h>
2#include <sys/time.h>
3#include <sys/resource.h>
1#include "symbol.h" 4#include "symbol.h"
2#include "dso.h" 5#include "dso.h"
3#include "machine.h" 6#include "machine.h"
@@ -136,7 +139,48 @@ int dso__read_binary_type_filename(const struct dso *dso,
136 return ret; 139 return ret;
137} 140}
138 141
139static int open_dso(struct dso *dso, struct machine *machine) 142/*
143 * Global list of open DSOs and the counter.
144 */
145static LIST_HEAD(dso__data_open);
146static long dso__data_open_cnt;
147
148static void dso__list_add(struct dso *dso)
149{
150 list_add_tail(&dso->data.open_entry, &dso__data_open);
151 dso__data_open_cnt++;
152}
153
154static void dso__list_del(struct dso *dso)
155{
156 list_del(&dso->data.open_entry);
157 WARN_ONCE(dso__data_open_cnt <= 0,
158 "DSO data fd counter out of bounds.");
159 dso__data_open_cnt--;
160}
161
162static void close_first_dso(void);
163
164static int do_open(char *name)
165{
166 int fd;
167
168 do {
169 fd = open(name, O_RDONLY);
170 if (fd >= 0)
171 return fd;
172
173 pr_debug("dso open failed, mmap: %s\n", strerror(errno));
174 if (!dso__data_open_cnt || errno != EMFILE)
175 break;
176
177 close_first_dso();
178 } while (1);
179
180 return -1;
181}
182
183static int __open_dso(struct dso *dso, struct machine *machine)
140{ 184{
141 int fd; 185 int fd;
142 char *root_dir = (char *)""; 186 char *root_dir = (char *)"";
@@ -154,11 +198,130 @@ static int open_dso(struct dso *dso, struct machine *machine)
154 return -EINVAL; 198 return -EINVAL;
155 } 199 }
156 200
157 fd = open(name, O_RDONLY); 201 fd = do_open(name);
158 free(name); 202 free(name);
159 return fd; 203 return fd;
160} 204}
161 205
206static void check_data_close(void);
207
208/**
209 * dso_close - Open DSO data file
210 * @dso: dso object
211 *
212 * Open @dso's data file descriptor and updates
213 * list/count of open DSO objects.
214 */
215static int open_dso(struct dso *dso, struct machine *machine)
216{
217 int fd = __open_dso(dso, machine);
218
219 if (fd > 0) {
220 dso__list_add(dso);
221 /*
222 * Check if we crossed the allowed number
223 * of opened DSOs and close one if needed.
224 */
225 check_data_close();
226 }
227
228 return fd;
229}
230
231static void close_data_fd(struct dso *dso)
232{
233 if (dso->data.fd >= 0) {
234 close(dso->data.fd);
235 dso->data.fd = -1;
236 dso->data.file_size = 0;
237 dso__list_del(dso);
238 }
239}
240
241/**
242 * dso_close - Close DSO data file
243 * @dso: dso object
244 *
245 * Close @dso's data file descriptor and updates
246 * list/count of open DSO objects.
247 */
248static void close_dso(struct dso *dso)
249{
250 close_data_fd(dso);
251}
252
253static void close_first_dso(void)
254{
255 struct dso *dso;
256
257 dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
258 close_dso(dso);
259}
260
261static rlim_t get_fd_limit(void)
262{
263 struct rlimit l;
264 rlim_t limit = 0;
265
266 /* Allow half of the current open fd limit. */
267 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
268 if (l.rlim_cur == RLIM_INFINITY)
269 limit = l.rlim_cur;
270 else
271 limit = l.rlim_cur / 2;
272 } else {
273 pr_err("failed to get fd limit\n");
274 limit = 1;
275 }
276
277 return limit;
278}
279
280static bool may_cache_fd(void)
281{
282 static rlim_t limit;
283
284 if (!limit)
285 limit = get_fd_limit();
286
287 if (limit == RLIM_INFINITY)
288 return true;
289
290 return limit > (rlim_t) dso__data_open_cnt;
291}
292
293/*
294 * Check and close LRU dso if we crossed allowed limit
295 * for opened dso file descriptors. The limit is half
296 * of the RLIMIT_NOFILE files opened.
297*/
298static void check_data_close(void)
299{
300 bool cache_fd = may_cache_fd();
301
302 if (!cache_fd)
303 close_first_dso();
304}
305
306/**
307 * dso__data_close - Close DSO data file
308 * @dso: dso object
309 *
310 * External interface to close @dso's data file descriptor.
311 */
312void dso__data_close(struct dso *dso)
313{
314 close_dso(dso);
315}
316
317/**
318 * dso__data_fd - Get dso's data file descriptor
319 * @dso: dso object
320 * @machine: machine object
321 *
322 * External interface to find dso's file, open it and
323 * returns file descriptor.
324 */
162int dso__data_fd(struct dso *dso, struct machine *machine) 325int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 326{
164 enum dso_binary_type binary_type_data[] = { 327 enum dso_binary_type binary_type_data[] = {
@@ -168,8 +331,13 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
168 }; 331 };
169 int i = 0; 332 int i = 0;
170 333
171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) 334 if (dso->data.fd >= 0)
172 return open_dso(dso, machine); 335 return dso->data.fd;
336
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd;
340 }
173 341
174 do { 342 do {
175 int fd; 343 int fd;
@@ -178,7 +346,7 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
178 346
179 fd = open_dso(dso, machine); 347 fd = open_dso(dso, machine);
180 if (fd >= 0) 348 if (fd >= 0)
181 return fd; 349 return dso->data.fd = fd;
182 350
183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 352
@@ -260,16 +428,10 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset,
260} 428}
261 429
262static ssize_t 430static ssize_t
263dso_cache__read(struct dso *dso, struct machine *machine, 431dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
264 u64 offset, u8 *data, ssize_t size)
265{ 432{
266 struct dso_cache *cache; 433 struct dso_cache *cache;
267 ssize_t ret; 434 ssize_t ret;
268 int fd;
269
270 fd = dso__data_fd(dso, machine);
271 if (fd < 0)
272 return -1;
273 435
274 do { 436 do {
275 u64 cache_offset; 437 u64 cache_offset;
@@ -283,16 +445,16 @@ dso_cache__read(struct dso *dso, struct machine *machine,
283 cache_offset = offset & DSO__DATA_CACHE_MASK; 445 cache_offset = offset & DSO__DATA_CACHE_MASK;
284 ret = -EINVAL; 446 ret = -EINVAL;
285 447
286 if (-1 == lseek(fd, cache_offset, SEEK_SET)) 448 if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET))
287 break; 449 break;
288 450
289 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 451 ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
290 if (ret <= 0) 452 if (ret <= 0)
291 break; 453 break;
292 454
293 cache->offset = cache_offset; 455 cache->offset = cache_offset;
294 cache->size = ret; 456 cache->size = ret;
295 dso_cache__insert(&dso->cache, cache); 457 dso_cache__insert(&dso->data.cache, cache);
296 458
297 ret = dso_cache__memcpy(cache, offset, data, size); 459 ret = dso_cache__memcpy(cache, offset, data, size);
298 460
@@ -301,24 +463,27 @@ dso_cache__read(struct dso *dso, struct machine *machine,
301 if (ret <= 0) 463 if (ret <= 0)
302 free(cache); 464 free(cache);
303 465
304 close(fd);
305 return ret; 466 return ret;
306} 467}
307 468
308static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 469static ssize_t dso_cache_read(struct dso *dso, u64 offset,
309 u64 offset, u8 *data, ssize_t size) 470 u8 *data, ssize_t size)
310{ 471{
311 struct dso_cache *cache; 472 struct dso_cache *cache;
312 473
313 cache = dso_cache__find(&dso->cache, offset); 474 cache = dso_cache__find(&dso->data.cache, offset);
314 if (cache) 475 if (cache)
315 return dso_cache__memcpy(cache, offset, data, size); 476 return dso_cache__memcpy(cache, offset, data, size);
316 else 477 else
317 return dso_cache__read(dso, machine, offset, data, size); 478 return dso_cache__read(dso, offset, data, size);
318} 479}
319 480
320ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 481/*
321 u64 offset, u8 *data, ssize_t size) 482 * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
483 * in the rb_tree. Any read to already cached data is served
484 * by cached data.
485 */
486static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
322{ 487{
323 ssize_t r = 0; 488 ssize_t r = 0;
324 u8 *p = data; 489 u8 *p = data;
@@ -326,7 +491,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
326 do { 491 do {
327 ssize_t ret; 492 ssize_t ret;
328 493
329 ret = dso_cache_read(dso, machine, offset, p, size); 494 ret = dso_cache_read(dso, offset, p, size);
330 if (ret < 0) 495 if (ret < 0)
331 return ret; 496 return ret;
332 497
@@ -346,6 +511,67 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
346 return r; 511 return r;
347} 512}
348 513
514static int data_file_size(struct dso *dso)
515{
516 struct stat st;
517
518 if (!dso->data.file_size) {
519 if (fstat(dso->data.fd, &st)) {
520 pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
521 return -1;
522 }
523 dso->data.file_size = st.st_size;
524 }
525
526 return 0;
527}
528
529static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size)
531{
532 if (data_file_size(dso))
533 return -1;
534
535 /* Check the offset sanity. */
536 if (offset > dso->data.file_size)
537 return -1;
538
539 if (offset + size < offset)
540 return -1;
541
542 return cached_read(dso, offset, data, size);
543}
544
545/**
546 * dso__data_read_offset - Read data from dso file offset
547 * @dso: dso object
548 * @machine: machine object
549 * @offset: file offset
550 * @data: buffer to store data
551 * @size: size of the @data buffer
552 *
553 * External interface to read data from dso file offset. Open
554 * dso data file and use cached_read to get the data.
555 */
556ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
557 u64 offset, u8 *data, ssize_t size)
558{
559 if (dso__data_fd(dso, machine) < 0)
560 return -1;
561
562 return data_read_offset(dso, offset, data, size);
563}
564
565/**
566 * dso__data_read_addr - Read data from dso address
567 * @dso: dso object
568 * @machine: machine object
569 * @add: virtual memory address
570 * @data: buffer to store data
571 * @size: size of the @data buffer
572 *
573 * External interface to read data from dso address.
574 */
349ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 575ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
350 struct machine *machine, u64 addr, 576 struct machine *machine, u64 addr,
351 u8 *data, ssize_t size) 577 u8 *data, ssize_t size)
@@ -473,7 +699,8 @@ struct dso *dso__new(const char *name)
473 dso__set_short_name(dso, dso->name, false); 699 dso__set_short_name(dso, dso->name, false);
474 for (i = 0; i < MAP__NR_TYPES; ++i) 700 for (i = 0; i < MAP__NR_TYPES; ++i)
475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
476 dso->cache = RB_ROOT; 702 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1;
477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
479 dso->loaded = 0; 706 dso->loaded = 0;
@@ -485,6 +712,7 @@ struct dso *dso__new(const char *name)
485 dso->kernel = DSO_TYPE_USER; 712 dso->kernel = DSO_TYPE_USER;
486 dso->needs_swap = DSO_SWAP__UNSET; 713 dso->needs_swap = DSO_SWAP__UNSET;
487 INIT_LIST_HEAD(&dso->node); 714 INIT_LIST_HEAD(&dso->node);
715 INIT_LIST_HEAD(&dso->data.open_entry);
488 } 716 }
489 717
490 return dso; 718 return dso;
@@ -506,7 +734,8 @@ void dso__delete(struct dso *dso)
506 dso->long_name_allocated = false; 734 dso->long_name_allocated = false;
507 } 735 }
508 736
509 dso_cache__free(&dso->cache); 737 dso__data_close(dso);
738 dso_cache__free(&dso->data.cache);
510 dso__free_a2l(dso); 739 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename); 740 zfree(&dso->symsrc_filename);
512 free(dso); 741 free(dso);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 38efe95a7fdd..ad553ba257bf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -76,7 +76,6 @@ struct dso {
76 struct list_head node; 76 struct list_head node;
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache;
80 void *a2l; 79 void *a2l;
81 char *symsrc_filename; 80 char *symsrc_filename;
82 unsigned int a2l_fails; 81 unsigned int a2l_fails;
@@ -99,6 +98,15 @@ struct dso {
99 const char *long_name; 98 const char *long_name;
100 u16 long_name_len; 99 u16 long_name_len;
101 u16 short_name_len; 100 u16 short_name_len;
101
102 /* dso data file */
103 struct {
104 struct rb_root cache;
105 int fd;
106 size_t file_size;
107 struct list_head open_entry;
108 } data;
109
102 char name[0]; 110 char name[0];
103}; 111};
104 112
@@ -141,7 +149,47 @@ char dso__symtab_origin(const struct dso *dso);
141int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 149int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
142 char *root_dir, char *filename, size_t size); 150 char *root_dir, char *filename, size_t size);
143 151
152/*
153 * The dso__data_* external interface provides following functions:
154 * dso__data_fd
155 * dso__data_close
156 * dso__data_read_offset
157 * dso__data_read_addr
158 *
159 * Please refer to the dso.c object code for each function and
160 * arguments documentation. Following text tries to explain the
161 * dso file descriptor caching.
162 *
163 * The dso__data* interface allows caching of opened file descriptors
164 * to speed up the dso data accesses. The idea is to leave the file
165 * descriptor opened ideally for the whole life of the dso object.
166 *
167 * The current usage of the dso__data_* interface is as follows:
168 *
169 * Get DSO's fd:
170 * int fd = dso__data_fd(dso, machine);
171 * USE 'fd' SOMEHOW
172 *
173 * Read DSO's data:
174 * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE);
175 * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE);
176 *
177 * Eventually close DSO's fd:
178 * dso__data_close(dso);
179 *
180 * It is not necessary to close the DSO object data file. Each time new
181 * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once
182 * it is crossed, the oldest opened DSO object is closed.
183 *
184 * The dso__delete function calls close_dso function to ensure the
185 * data file descriptor gets closed/unmapped before the dso object
186 * is freed.
187 *
188 * TODO
189*/
144int dso__data_fd(struct dso *dso, struct machine *machine); 190int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso);
192
145ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
146 u64 offset, u8 *data, ssize_t size); 194 u64 offset, u8 *data, ssize_t size);
147ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 195ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 7defd77105d0..cc66c4049e09 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -747,14 +747,17 @@ struct __find_variable_param {
747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
748{ 748{
749 struct __find_variable_param *fvp = data; 749 struct __find_variable_param *fvp = data;
750 Dwarf_Attribute attr;
750 int tag; 751 int tag;
751 752
752 tag = dwarf_tag(die_mem); 753 tag = dwarf_tag(die_mem);
753 if ((tag == DW_TAG_formal_parameter || 754 if ((tag == DW_TAG_formal_parameter ||
754 tag == DW_TAG_variable) && 755 tag == DW_TAG_variable) &&
755 die_compare_name(die_mem, fvp->name)) 756 die_compare_name(die_mem, fvp->name) &&
757 /* Does the DIE have location information or external instance? */
758 (dwarf_attr(die_mem, DW_AT_external, &attr) ||
759 dwarf_attr(die_mem, DW_AT_location, &attr)))
756 return DIE_FIND_CB_END; 760 return DIE_FIND_CB_END;
757
758 if (dwarf_haspc(die_mem, fvp->addr)) 761 if (dwarf_haspc(die_mem, fvp->addr))
759 return DIE_FIND_CB_CONTINUE; 762 return DIE_FIND_CB_CONTINUE;
760 else 763 else
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 65795b835b39..d0281bdfa582 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,4 +1,5 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include <sys/mman.h>
2#include "event.h" 3#include "event.h"
3#include "debug.h" 4#include "debug.h"
4#include "hist.h" 5#include "hist.h"
@@ -178,13 +179,14 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
178 return -1; 179 return -1;
179 } 180 }
180 181
181 event->header.type = PERF_RECORD_MMAP; 182 event->header.type = PERF_RECORD_MMAP2;
182 183
183 while (1) { 184 while (1) {
184 char bf[BUFSIZ]; 185 char bf[BUFSIZ];
185 char prot[5]; 186 char prot[5];
186 char execname[PATH_MAX]; 187 char execname[PATH_MAX];
187 char anonstr[] = "//anon"; 188 char anonstr[] = "//anon";
189 unsigned int ino;
188 size_t size; 190 size_t size;
189 ssize_t n; 191 ssize_t n;
190 192
@@ -195,15 +197,20 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
195 strcpy(execname, ""); 197 strcpy(execname, "");
196 198
197 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 199 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
198 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 200 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
199 &event->mmap.start, &event->mmap.len, prot, 201 &event->mmap2.start, &event->mmap2.len, prot,
200 &event->mmap.pgoff, 202 &event->mmap2.pgoff, &event->mmap2.maj,
201 execname); 203 &event->mmap2.min,
204 &ino, execname);
205
202 /* 206 /*
203 * Anon maps don't have the execname. 207 * Anon maps don't have the execname.
204 */ 208 */
205 if (n < 4) 209 if (n < 7)
206 continue; 210 continue;
211
212 event->mmap2.ino = (u64)ino;
213
207 /* 214 /*
208 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 215 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
209 */ 216 */
@@ -212,6 +219,21 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
212 else 219 else
213 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 220 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
214 221
222 /* map protection and flags bits */
223 event->mmap2.prot = 0;
224 event->mmap2.flags = 0;
225 if (prot[0] == 'r')
226 event->mmap2.prot |= PROT_READ;
227 if (prot[1] == 'w')
228 event->mmap2.prot |= PROT_WRITE;
229 if (prot[2] == 'x')
230 event->mmap2.prot |= PROT_EXEC;
231
232 if (prot[3] == 's')
233 event->mmap2.flags |= MAP_SHARED;
234 else
235 event->mmap2.flags |= MAP_PRIVATE;
236
215 if (prot[2] != 'x') { 237 if (prot[2] != 'x') {
216 if (!mmap_data || prot[0] != 'r') 238 if (!mmap_data || prot[0] != 'r')
217 continue; 239 continue;
@@ -223,15 +245,15 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
223 strcpy(execname, anonstr); 245 strcpy(execname, anonstr);
224 246
225 size = strlen(execname) + 1; 247 size = strlen(execname) + 1;
226 memcpy(event->mmap.filename, execname, size); 248 memcpy(event->mmap2.filename, execname, size);
227 size = PERF_ALIGN(size, sizeof(u64)); 249 size = PERF_ALIGN(size, sizeof(u64));
228 event->mmap.len -= event->mmap.start; 250 event->mmap2.len -= event->mmap.start;
229 event->mmap.header.size = (sizeof(event->mmap) - 251 event->mmap2.header.size = (sizeof(event->mmap2) -
230 (sizeof(event->mmap.filename) - size)); 252 (sizeof(event->mmap2.filename) - size));
231 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 253 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
232 event->mmap.header.size += machine->id_hdr_size; 254 event->mmap2.header.size += machine->id_hdr_size;
233 event->mmap.pid = tgid; 255 event->mmap2.pid = tgid;
234 event->mmap.tid = pid; 256 event->mmap2.tid = pid;
235 257
236 if (process(tool, event, &synth_sample, machine) != 0) { 258 if (process(tool, event, &synth_sample, machine) != 0) {
237 rc = -1; 259 rc = -1;
@@ -612,12 +634,15 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
612size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 634size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
613{ 635{
614 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 636 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
615 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n", 637 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n",
616 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 638 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
617 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 639 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
618 event->mmap2.min, event->mmap2.ino, 640 event->mmap2.min, event->mmap2.ino,
619 event->mmap2.ino_generation, 641 event->mmap2.ino_generation,
620 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 642 (event->mmap2.prot & PROT_READ) ? 'r' : '-',
643 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
644 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
645 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
621 event->mmap2.filename); 646 event->mmap2.filename);
622} 647}
623 648
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d970232cb270..e5dd40addb30 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -7,6 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10#include "perf_regs.h"
10 11
11struct mmap_event { 12struct mmap_event {
12 struct perf_event_header header; 13 struct perf_event_header header;
@@ -27,6 +28,8 @@ struct mmap2_event {
27 u32 min; 28 u32 min;
28 u64 ino; 29 u64 ino;
29 u64 ino_generation; 30 u64 ino_generation;
31 u32 prot;
32 u32 flags;
30 char filename[PATH_MAX]; 33 char filename[PATH_MAX];
31}; 34};
32 35
@@ -87,6 +90,10 @@ struct regs_dump {
87 u64 abi; 90 u64 abi;
88 u64 mask; 91 u64 mask;
89 u64 *regs; 92 u64 *regs;
93
94 /* Cached values/mask filled by first register access. */
95 u64 cache_regs[PERF_REGS_MAX];
96 u64 cache_mask;
90}; 97};
91 98
92struct stack_dump { 99struct stack_dump {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5c28d82b76c4..8606175fe1e8 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -589,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
589 } 589 }
590 590
591 /* 591 /*
592 * We default some events to a 1 default interval. But keep 592 * We default some events to have a default interval. But keep
593 * it a weak assumption overridable by the user. 593 * it a weak assumption overridable by the user.
594 */ 594 */
595 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 595 if (!attr->sample_period || (opts->user_freq != UINT_MAX ||
596 opts->user_interval != ULLONG_MAX)) { 596 opts->user_interval != ULLONG_MAX)) {
597 if (opts->freq) { 597 if (opts->freq) {
598 perf_evsel__set_sample_bit(evsel, PERIOD); 598 perf_evsel__set_sample_bit(evsel, PERIOD);
@@ -659,6 +659,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
659 perf_evsel__set_sample_bit(evsel, WEIGHT); 659 perf_evsel__set_sample_bit(evsel, WEIGHT);
660 660
661 attr->mmap = track; 661 attr->mmap = track;
662 attr->mmap2 = track && !perf_missing_features.mmap2;
662 attr->comm = track; 663 attr->comm = track;
663 664
664 if (opts->sample_transaction) 665 if (opts->sample_transaction)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b262b44b7a65..30df6187ee02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "annotate.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -127,6 +128,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
127 + unresolved_col_width + 2; 128 + unresolved_col_width + 2;
128 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
129 symlen); 130 symlen);
131 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
132 symlen + 1);
130 } else { 133 } else {
131 symlen = unresolved_col_width + 4 + 2; 134 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
@@ -231,6 +234,8 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
231 return true; 234 return true;
232 235
233 he_stat__decay(&he->stat); 236 he_stat__decay(&he->stat);
237 if (symbol_conf.cumulate_callchain)
238 he_stat__decay(he->stat_acc);
234 239
235 diff = prev_period - he->stat.period; 240 diff = prev_period - he->stat.period;
236 241
@@ -276,14 +281,31 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
276 * histogram, sorted on item, collects periods 281 * histogram, sorted on item, collects periods
277 */ 282 */
278 283
279static struct hist_entry *hist_entry__new(struct hist_entry *template) 284static struct hist_entry *hist_entry__new(struct hist_entry *template,
285 bool sample_self)
280{ 286{
281 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 287 size_t callchain_size = 0;
282 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 288 struct hist_entry *he;
289
290 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
291 callchain_size = sizeof(struct callchain_root);
292
293 he = zalloc(sizeof(*he) + callchain_size);
283 294
284 if (he != NULL) { 295 if (he != NULL) {
285 *he = *template; 296 *he = *template;
286 297
298 if (symbol_conf.cumulate_callchain) {
299 he->stat_acc = malloc(sizeof(he->stat));
300 if (he->stat_acc == NULL) {
301 free(he);
302 return NULL;
303 }
304 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
305 if (!sample_self)
306 memset(&he->stat, 0, sizeof(he->stat));
307 }
308
287 if (he->ms.map) 309 if (he->ms.map)
288 he->ms.map->referenced = true; 310 he->ms.map->referenced = true;
289 311
@@ -295,6 +317,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
295 */ 317 */
296 he->branch_info = malloc(sizeof(*he->branch_info)); 318 he->branch_info = malloc(sizeof(*he->branch_info));
297 if (he->branch_info == NULL) { 319 if (he->branch_info == NULL) {
320 free(he->stat_acc);
298 free(he); 321 free(he);
299 return NULL; 322 return NULL;
300 } 323 }
@@ -333,7 +356,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
333 356
334static struct hist_entry *add_hist_entry(struct hists *hists, 357static struct hist_entry *add_hist_entry(struct hists *hists,
335 struct hist_entry *entry, 358 struct hist_entry *entry,
336 struct addr_location *al) 359 struct addr_location *al,
360 bool sample_self)
337{ 361{
338 struct rb_node **p; 362 struct rb_node **p;
339 struct rb_node *parent = NULL; 363 struct rb_node *parent = NULL;
@@ -357,7 +381,10 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
357 cmp = hist_entry__cmp(he, entry); 381 cmp = hist_entry__cmp(he, entry);
358 382
359 if (!cmp) { 383 if (!cmp) {
360 he_stat__add_period(&he->stat, period, weight); 384 if (sample_self)
385 he_stat__add_period(&he->stat, period, weight);
386 if (symbol_conf.cumulate_callchain)
387 he_stat__add_period(he->stat_acc, period, weight);
361 388
362 /* 389 /*
363 * This mem info was allocated from sample__resolve_mem 390 * This mem info was allocated from sample__resolve_mem
@@ -385,14 +412,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
385 p = &(*p)->rb_right; 412 p = &(*p)->rb_right;
386 } 413 }
387 414
388 he = hist_entry__new(entry); 415 he = hist_entry__new(entry, sample_self);
389 if (!he) 416 if (!he)
390 return NULL; 417 return NULL;
391 418
392 rb_link_node(&he->rb_node_in, parent, p); 419 rb_link_node(&he->rb_node_in, parent, p);
393 rb_insert_color(&he->rb_node_in, hists->entries_in); 420 rb_insert_color(&he->rb_node_in, hists->entries_in);
394out: 421out:
395 he_stat__add_cpumode_period(&he->stat, al->cpumode, period); 422 if (sample_self)
423 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
424 if (symbol_conf.cumulate_callchain)
425 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
396 return he; 426 return he;
397} 427}
398 428
@@ -401,7 +431,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
401 struct symbol *sym_parent, 431 struct symbol *sym_parent,
402 struct branch_info *bi, 432 struct branch_info *bi,
403 struct mem_info *mi, 433 struct mem_info *mi,
404 u64 period, u64 weight, u64 transaction) 434 u64 period, u64 weight, u64 transaction,
435 bool sample_self)
405{ 436{
406 struct hist_entry entry = { 437 struct hist_entry entry = {
407 .thread = al->thread, 438 .thread = al->thread,
@@ -410,9 +441,10 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
410 .map = al->map, 441 .map = al->map,
411 .sym = al->sym, 442 .sym = al->sym,
412 }, 443 },
413 .cpu = al->cpu, 444 .cpu = al->cpu,
414 .ip = al->addr, 445 .cpumode = al->cpumode,
415 .level = al->level, 446 .ip = al->addr,
447 .level = al->level,
416 .stat = { 448 .stat = {
417 .nr_events = 1, 449 .nr_events = 1,
418 .period = period, 450 .period = period,
@@ -426,7 +458,429 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
426 .transaction = transaction, 458 .transaction = transaction,
427 }; 459 };
428 460
429 return add_hist_entry(hists, &entry, al); 461 return add_hist_entry(hists, &entry, al, sample_self);
462}
463
464static int
465iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
466 struct addr_location *al __maybe_unused)
467{
468 return 0;
469}
470
471static int
472iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
473 struct addr_location *al __maybe_unused)
474{
475 return 0;
476}
477
478static int
479iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
480{
481 struct perf_sample *sample = iter->sample;
482 struct mem_info *mi;
483
484 mi = sample__resolve_mem(sample, al);
485 if (mi == NULL)
486 return -ENOMEM;
487
488 iter->priv = mi;
489 return 0;
490}
491
492static int
493iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
494{
495 u64 cost;
496 struct mem_info *mi = iter->priv;
497 struct hist_entry *he;
498
499 if (mi == NULL)
500 return -EINVAL;
501
502 cost = iter->sample->weight;
503 if (!cost)
504 cost = 1;
505
506 /*
507 * must pass period=weight in order to get the correct
508 * sorting from hists__collapse_resort() which is solely
509 * based on periods. We want sorting be done on nr_events * weight
510 * and this is indirectly achieved by passing period=weight here
511 * and the he_stat__add_period() function.
512 */
513 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi,
514 cost, cost, 0, true);
515 if (!he)
516 return -ENOMEM;
517
518 iter->he = he;
519 return 0;
520}
521
522static int
523iter_finish_mem_entry(struct hist_entry_iter *iter,
524 struct addr_location *al __maybe_unused)
525{
526 struct perf_evsel *evsel = iter->evsel;
527 struct hist_entry *he = iter->he;
528 int err = -EINVAL;
529
530 if (he == NULL)
531 goto out;
532
533 hists__inc_nr_samples(&evsel->hists, he->filtered);
534
535 err = hist_entry__append_callchain(he, iter->sample);
536
537out:
538 /*
539 * We don't need to free iter->priv (mem_info) here since
540 * the mem info was either already freed in add_hist_entry() or
541 * passed to a new hist entry by hist_entry__new().
542 */
543 iter->priv = NULL;
544
545 iter->he = NULL;
546 return err;
547}
548
549static int
550iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
551{
552 struct branch_info *bi;
553 struct perf_sample *sample = iter->sample;
554
555 bi = sample__resolve_bstack(sample, al);
556 if (!bi)
557 return -ENOMEM;
558
559 iter->curr = 0;
560 iter->total = sample->branch_stack->nr;
561
562 iter->priv = bi;
563 return 0;
564}
565
566static int
567iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
568 struct addr_location *al __maybe_unused)
569{
570 /* to avoid calling callback function */
571 iter->he = NULL;
572
573 return 0;
574}
575
576static int
577iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
578{
579 struct branch_info *bi = iter->priv;
580 int i = iter->curr;
581
582 if (bi == NULL)
583 return 0;
584
585 if (iter->curr >= iter->total)
586 return 0;
587
588 al->map = bi[i].to.map;
589 al->sym = bi[i].to.sym;
590 al->addr = bi[i].to.addr;
591 return 1;
592}
593
594static int
595iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
596{
597 struct branch_info *bi;
598 struct perf_evsel *evsel = iter->evsel;
599 struct hist_entry *he = NULL;
600 int i = iter->curr;
601 int err = 0;
602
603 bi = iter->priv;
604
605 if (iter->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
606 goto out;
607
608 /*
609 * The report shows the percentage of total branches captured
610 * and not events sampled. Thus we use a pseudo period of 1.
611 */
612 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL,
613 1, 1, 0, true);
614 if (he == NULL)
615 return -ENOMEM;
616
617 hists__inc_nr_samples(&evsel->hists, he->filtered);
618
619out:
620 iter->he = he;
621 iter->curr++;
622 return err;
623}
624
625static int
626iter_finish_branch_entry(struct hist_entry_iter *iter,
627 struct addr_location *al __maybe_unused)
628{
629 zfree(&iter->priv);
630 iter->he = NULL;
631
632 return iter->curr >= iter->total ? 0 : -1;
633}
634
635static int
636iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
637 struct addr_location *al __maybe_unused)
638{
639 return 0;
640}
641
642static int
643iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
644{
645 struct perf_evsel *evsel = iter->evsel;
646 struct perf_sample *sample = iter->sample;
647 struct hist_entry *he;
648
649 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
650 sample->period, sample->weight,
651 sample->transaction, true);
652 if (he == NULL)
653 return -ENOMEM;
654
655 iter->he = he;
656 return 0;
657}
658
659static int
660iter_finish_normal_entry(struct hist_entry_iter *iter,
661 struct addr_location *al __maybe_unused)
662{
663 struct hist_entry *he = iter->he;
664 struct perf_evsel *evsel = iter->evsel;
665 struct perf_sample *sample = iter->sample;
666
667 if (he == NULL)
668 return 0;
669
670 iter->he = NULL;
671
672 hists__inc_nr_samples(&evsel->hists, he->filtered);
673
674 return hist_entry__append_callchain(he, sample);
675}
676
677static int
678iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
679 struct addr_location *al __maybe_unused)
680{
681 struct hist_entry **he_cache;
682
683 callchain_cursor_commit(&callchain_cursor);
684
685 /*
686 * This is for detecting cycles or recursions so that they're
687 * cumulated only one time to prevent entries more than 100%
688 * overhead.
689 */
690 he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
691 if (he_cache == NULL)
692 return -ENOMEM;
693
694 iter->priv = he_cache;
695 iter->curr = 0;
696
697 return 0;
698}
699
700static int
701iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
702 struct addr_location *al)
703{
704 struct perf_evsel *evsel = iter->evsel;
705 struct perf_sample *sample = iter->sample;
706 struct hist_entry **he_cache = iter->priv;
707 struct hist_entry *he;
708 int err = 0;
709
710 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
711 sample->period, sample->weight,
712 sample->transaction, true);
713 if (he == NULL)
714 return -ENOMEM;
715
716 iter->he = he;
717 he_cache[iter->curr++] = he;
718
719 callchain_append(he->callchain, &callchain_cursor, sample->period);
720
721 /*
722 * We need to re-initialize the cursor since callchain_append()
723 * advanced the cursor to the end.
724 */
725 callchain_cursor_commit(&callchain_cursor);
726
727 hists__inc_nr_samples(&evsel->hists, he->filtered);
728
729 return err;
730}
731
732static int
733iter_next_cumulative_entry(struct hist_entry_iter *iter,
734 struct addr_location *al)
735{
736 struct callchain_cursor_node *node;
737
738 node = callchain_cursor_current(&callchain_cursor);
739 if (node == NULL)
740 return 0;
741
742 return fill_callchain_info(al, node, iter->hide_unresolved);
743}
744
745static int
746iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
747 struct addr_location *al)
748{
749 struct perf_evsel *evsel = iter->evsel;
750 struct perf_sample *sample = iter->sample;
751 struct hist_entry **he_cache = iter->priv;
752 struct hist_entry *he;
753 struct hist_entry he_tmp = {
754 .cpu = al->cpu,
755 .thread = al->thread,
756 .comm = thread__comm(al->thread),
757 .ip = al->addr,
758 .ms = {
759 .map = al->map,
760 .sym = al->sym,
761 },
762 .parent = iter->parent,
763 };
764 int i;
765 struct callchain_cursor cursor;
766
767 callchain_cursor_snapshot(&cursor, &callchain_cursor);
768
769 callchain_cursor_advance(&callchain_cursor);
770
771 /*
772 * Check if there's duplicate entries in the callchain.
773 * It's possible that it has cycles or recursive calls.
774 */
775 for (i = 0; i < iter->curr; i++) {
776 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
777 /* to avoid calling callback function */
778 iter->he = NULL;
779 return 0;
780 }
781 }
782
783 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
784 sample->period, sample->weight,
785 sample->transaction, false);
786 if (he == NULL)
787 return -ENOMEM;
788
789 iter->he = he;
790 he_cache[iter->curr++] = he;
791
792 callchain_append(he->callchain, &cursor, sample->period);
793 return 0;
794}
795
796static int
797iter_finish_cumulative_entry(struct hist_entry_iter *iter,
798 struct addr_location *al __maybe_unused)
799{
800 zfree(&iter->priv);
801 iter->he = NULL;
802
803 return 0;
804}
805
806const struct hist_iter_ops hist_iter_mem = {
807 .prepare_entry = iter_prepare_mem_entry,
808 .add_single_entry = iter_add_single_mem_entry,
809 .next_entry = iter_next_nop_entry,
810 .add_next_entry = iter_add_next_nop_entry,
811 .finish_entry = iter_finish_mem_entry,
812};
813
814const struct hist_iter_ops hist_iter_branch = {
815 .prepare_entry = iter_prepare_branch_entry,
816 .add_single_entry = iter_add_single_branch_entry,
817 .next_entry = iter_next_branch_entry,
818 .add_next_entry = iter_add_next_branch_entry,
819 .finish_entry = iter_finish_branch_entry,
820};
821
822const struct hist_iter_ops hist_iter_normal = {
823 .prepare_entry = iter_prepare_normal_entry,
824 .add_single_entry = iter_add_single_normal_entry,
825 .next_entry = iter_next_nop_entry,
826 .add_next_entry = iter_add_next_nop_entry,
827 .finish_entry = iter_finish_normal_entry,
828};
829
830const struct hist_iter_ops hist_iter_cumulative = {
831 .prepare_entry = iter_prepare_cumulative_entry,
832 .add_single_entry = iter_add_single_cumulative_entry,
833 .next_entry = iter_next_cumulative_entry,
834 .add_next_entry = iter_add_next_cumulative_entry,
835 .finish_entry = iter_finish_cumulative_entry,
836};
837
838int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
839 struct perf_evsel *evsel, struct perf_sample *sample,
840 int max_stack_depth, void *arg)
841{
842 int err, err2;
843
844 err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
845 max_stack_depth);
846 if (err)
847 return err;
848
849 iter->evsel = evsel;
850 iter->sample = sample;
851
852 err = iter->ops->prepare_entry(iter, al);
853 if (err)
854 goto out;
855
856 err = iter->ops->add_single_entry(iter, al);
857 if (err)
858 goto out;
859
860 if (iter->he && iter->add_entry_cb) {
861 err = iter->add_entry_cb(iter, al, true, arg);
862 if (err)
863 goto out;
864 }
865
866 while (iter->ops->next_entry(iter, al)) {
867 err = iter->ops->add_next_entry(iter, al);
868 if (err)
869 break;
870
871 if (iter->he && iter->add_entry_cb) {
872 err = iter->add_entry_cb(iter, al, false, arg);
873 if (err)
874 goto out;
875 }
876 }
877
878out:
879 err2 = iter->ops->finish_entry(iter, al);
880 if (!err)
881 err = err2;
882
883 return err;
430} 884}
431 885
432int64_t 886int64_t
@@ -469,6 +923,7 @@ void hist_entry__free(struct hist_entry *he)
469{ 923{
470 zfree(&he->branch_info); 924 zfree(&he->branch_info);
471 zfree(&he->mem_info); 925 zfree(&he->mem_info);
926 zfree(&he->stat_acc);
472 free_srcline(he->srcline); 927 free_srcline(he->srcline);
473 free(he); 928 free(he);
474} 929}
@@ -494,6 +949,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
494 949
495 if (!cmp) { 950 if (!cmp) {
496 he_stat__add_stat(&iter->stat, &he->stat); 951 he_stat__add_stat(&iter->stat, &he->stat);
952 if (symbol_conf.cumulate_callchain)
953 he_stat__add_stat(iter->stat_acc, he->stat_acc);
497 954
498 if (symbol_conf.use_callchain) { 955 if (symbol_conf.use_callchain) {
499 callchain_cursor_reset(&callchain_cursor); 956 callchain_cursor_reset(&callchain_cursor);
@@ -800,6 +1257,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
800 events_stats__inc(&hists->stats, type); 1257 events_stats__inc(&hists->stats, type);
801} 1258}
802 1259
1260void hists__inc_nr_samples(struct hists *hists, bool filtered)
1261{
1262 events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
1263 if (!filtered)
1264 hists->stats.nr_non_filtered_samples++;
1265}
1266
803static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 1267static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
804 struct hist_entry *pair) 1268 struct hist_entry *pair)
805{ 1269{
@@ -831,7 +1295,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
831 p = &(*p)->rb_right; 1295 p = &(*p)->rb_right;
832 } 1296 }
833 1297
834 he = hist_entry__new(pair); 1298 he = hist_entry__new(pair, true);
835 if (he) { 1299 if (he) {
836 memset(&he->stat, 0, sizeof(he->stat)); 1300 memset(&he->stat, 0, sizeof(he->stat));
837 he->hists = hists; 1301 he->hists = hists;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a8418d19808d..742f49a85725 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -72,6 +72,7 @@ enum hist_column {
72 HISTC_MEM_TLB, 72 HISTC_MEM_TLB,
73 HISTC_MEM_LVL, 73 HISTC_MEM_LVL,
74 HISTC_MEM_SNOOP, 74 HISTC_MEM_SNOOP,
75 HISTC_MEM_DCACHELINE,
75 HISTC_TRANSACTION, 76 HISTC_TRANSACTION,
76 HISTC_NR_COLS, /* Last entry */ 77 HISTC_NR_COLS, /* Last entry */
77}; 78};
@@ -96,12 +97,50 @@ struct hists {
96 u16 col_len[HISTC_NR_COLS]; 97 u16 col_len[HISTC_NR_COLS];
97}; 98};
98 99
100struct hist_entry_iter;
101
102struct hist_iter_ops {
103 int (*prepare_entry)(struct hist_entry_iter *, struct addr_location *);
104 int (*add_single_entry)(struct hist_entry_iter *, struct addr_location *);
105 int (*next_entry)(struct hist_entry_iter *, struct addr_location *);
106 int (*add_next_entry)(struct hist_entry_iter *, struct addr_location *);
107 int (*finish_entry)(struct hist_entry_iter *, struct addr_location *);
108};
109
110struct hist_entry_iter {
111 int total;
112 int curr;
113
114 bool hide_unresolved;
115
116 struct perf_evsel *evsel;
117 struct perf_sample *sample;
118 struct hist_entry *he;
119 struct symbol *parent;
120 void *priv;
121
122 const struct hist_iter_ops *ops;
123 /* user-defined callback function (optional) */
124 int (*add_entry_cb)(struct hist_entry_iter *iter,
125 struct addr_location *al, bool single, void *arg);
126};
127
128extern const struct hist_iter_ops hist_iter_normal;
129extern const struct hist_iter_ops hist_iter_branch;
130extern const struct hist_iter_ops hist_iter_mem;
131extern const struct hist_iter_ops hist_iter_cumulative;
132
99struct hist_entry *__hists__add_entry(struct hists *hists, 133struct hist_entry *__hists__add_entry(struct hists *hists,
100 struct addr_location *al, 134 struct addr_location *al,
101 struct symbol *parent, 135 struct symbol *parent,
102 struct branch_info *bi, 136 struct branch_info *bi,
103 struct mem_info *mi, u64 period, 137 struct mem_info *mi, u64 period,
104 u64 weight, u64 transaction); 138 u64 weight, u64 transaction,
139 bool sample_self);
140int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
141 struct perf_evsel *evsel, struct perf_sample *sample,
142 int max_stack_depth, void *arg);
143
105int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
106int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 145int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
107int hist_entry__transaction_len(void); 146int hist_entry__transaction_len(void);
@@ -119,6 +158,7 @@ u64 hists__total_period(struct hists *hists);
119void hists__reset_stats(struct hists *hists); 158void hists__reset_stats(struct hists *hists);
120void hists__inc_stats(struct hists *hists, struct hist_entry *h); 159void hists__inc_stats(struct hists *hists, struct hist_entry *h);
121void hists__inc_nr_events(struct hists *hists, u32 type); 160void hists__inc_nr_events(struct hists *hists, u32 type);
161void hists__inc_nr_samples(struct hists *hists, bool filtered);
122void events_stats__inc(struct events_stats *stats, u32 type); 162void events_stats__inc(struct events_stats *stats, u32 type);
123size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 163size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
124 164
@@ -166,6 +206,7 @@ struct perf_hpp_fmt {
166 206
167 struct list_head list; 207 struct list_head list;
168 struct list_head sort_list; 208 struct list_head sort_list;
209 bool elide;
169}; 210};
170 211
171extern struct list_head perf_hpp__list; 212extern struct list_head perf_hpp__list;
@@ -192,6 +233,7 @@ enum {
192 PERF_HPP__OVERHEAD_US, 233 PERF_HPP__OVERHEAD_US,
193 PERF_HPP__OVERHEAD_GUEST_SYS, 234 PERF_HPP__OVERHEAD_GUEST_SYS,
194 PERF_HPP__OVERHEAD_GUEST_US, 235 PERF_HPP__OVERHEAD_GUEST_US,
236 PERF_HPP__OVERHEAD_ACC,
195 PERF_HPP__SAMPLES, 237 PERF_HPP__SAMPLES,
196 PERF_HPP__PERIOD, 238 PERF_HPP__PERIOD,
197 239
@@ -200,7 +242,11 @@ enum {
200 242
201void perf_hpp__init(void); 243void perf_hpp__init(void);
202void perf_hpp__column_register(struct perf_hpp_fmt *format); 244void perf_hpp__column_register(struct perf_hpp_fmt *format);
245void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
203void perf_hpp__column_enable(unsigned col); 246void perf_hpp__column_enable(unsigned col);
247void perf_hpp__column_disable(unsigned col);
248void perf_hpp__cancel_cumulate(void);
249
204void perf_hpp__register_sort_field(struct perf_hpp_fmt *format); 250void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
205void perf_hpp__setup_output_field(void); 251void perf_hpp__setup_output_field(void);
206void perf_hpp__reset_output_field(void); 252void perf_hpp__reset_output_field(void);
@@ -208,7 +254,12 @@ void perf_hpp__append_sort_keys(void);
208 254
209bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 255bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
210bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); 256bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
211bool perf_hpp__should_skip(struct perf_hpp_fmt *format); 257
258static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
259{
260 return format->elide;
261}
262
212void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 263void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
213 264
214typedef u64 (*hpp_field_fn)(struct hist_entry *he); 265typedef u64 (*hpp_field_fn)(struct hist_entry *he);
@@ -218,6 +269,9 @@ typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
218int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 269int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
219 hpp_field_fn get_field, const char *fmt, 270 hpp_field_fn get_field, const char *fmt,
220 hpp_snprint_fn print_fn, bool fmt_percent); 271 hpp_snprint_fn print_fn, bool fmt_percent);
272int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
273 hpp_field_fn get_field, const char *fmt,
274 hpp_snprint_fn print_fn, bool fmt_percent);
221 275
222static inline void advance_hpp(struct perf_hpp *hpp, int inc) 276static inline void advance_hpp(struct perf_hpp *hpp, int inc)
223{ 277{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 7409ac8de51c..0e5fea95d596 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1060,6 +1060,8 @@ int machine__process_mmap2_event(struct machine *machine,
1060 event->mmap2.pid, event->mmap2.maj, 1060 event->mmap2.pid, event->mmap2.maj,
1061 event->mmap2.min, event->mmap2.ino, 1061 event->mmap2.min, event->mmap2.ino,
1062 event->mmap2.ino_generation, 1062 event->mmap2.ino_generation,
1063 event->mmap2.prot,
1064 event->mmap2.flags,
1063 event->mmap2.filename, type); 1065 event->mmap2.filename, type);
1064 1066
1065 if (map == NULL) 1067 if (map == NULL)
@@ -1105,7 +1107,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1105 1107
1106 map = map__new(&machine->user_dsos, event->mmap.start, 1108 map = map__new(&machine->user_dsos, event->mmap.start,
1107 event->mmap.len, event->mmap.pgoff, 1109 event->mmap.len, event->mmap.pgoff,
1108 event->mmap.pid, 0, 0, 0, 0, 1110 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1109 event->mmap.filename, 1111 event->mmap.filename,
1110 type); 1112 type);
1111 1113
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 8ccbb32eda25..25c571f4cba6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -138,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
138 138
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, char *filename, 141 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 142 enum map_type type)
143{ 143{
144 struct map *map = malloc(sizeof(*map)); 144 struct map *map = malloc(sizeof(*map));
@@ -157,6 +157,8 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
157 map->min = d_min; 157 map->min = d_min;
158 map->ino = ino; 158 map->ino = ino;
159 map->ino_generation = ino_gen; 159 map->ino_generation = ino_gen;
160 map->prot = prot;
161 map->flags = flags;
160 162
161 if ((anon || no_dso) && type == MAP__FUNCTION) { 163 if ((anon || no_dso) && type == MAP__FUNCTION) {
162 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index ae2d45110588..7758c72522ef 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -35,6 +35,8 @@ struct map {
35 bool referenced; 35 bool referenced;
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u32 prot;
39 u32 flags;
38 u64 pgoff; 40 u64 pgoff;
39 u64 reloc; 41 u64 reloc;
40 u32 maj, min; /* only valid for MMAP2 record */ 42 u32 maj, min; /* only valid for MMAP2 record */
@@ -118,7 +120,7 @@ void map__init(struct map *map, enum map_type type,
118 u64 start, u64 end, u64 pgoff, struct dso *dso); 120 u64 start, u64 end, u64 pgoff, struct dso *dso);
119struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
120 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
121 u64 ino_gen, 123 u64 ino_gen, u32 prot, u32 flags,
122 char *filename, enum map_type type); 124 char *filename, enum map_type type);
123struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 125struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
124void map__delete(struct map *map); 126void map__delete(struct map *map);
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a3539ef30b15..43168fb0d9a2 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -1,11 +1,15 @@
1#include <errno.h> 1#include <errno.h>
2#include "perf_regs.h" 2#include "perf_regs.h"
3#include "event.h"
3 4
4int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 5int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
5{ 6{
6 int i, idx = 0; 7 int i, idx = 0;
7 u64 mask = regs->mask; 8 u64 mask = regs->mask;
8 9
10 if (regs->cache_mask & (1 << id))
11 goto out;
12
9 if (!(mask & (1 << id))) 13 if (!(mask & (1 << id)))
10 return -EINVAL; 14 return -EINVAL;
11 15
@@ -14,6 +18,10 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
14 idx++; 18 idx++;
15 } 19 }
16 20
17 *valp = regs->regs[idx]; 21 regs->cache_mask |= (1 << id);
22 regs->cache_regs[id] = regs->regs[idx];
23
24out:
25 *valp = regs->cache_regs[id];
18 return 0; 26 return 0;
19} 27}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 79c78f74e0cf..980dbf76bc98 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -2,7 +2,8 @@
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include "event.h" 5
6struct regs_dump;
6 7
7#ifdef HAVE_PERF_REGS_SUPPORT 8#ifdef HAVE_PERF_REGS_SUPPORT
8#include <perf_regs.h> 9#include <perf_regs.h>
@@ -11,6 +12,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
11 12
12#else 13#else
13#define PERF_REGS_MASK 0 14#define PERF_REGS_MASK 0
15#define PERF_REGS_MAX 0
14 16
15static inline const char *perf_reg_name(int id __maybe_unused) 17static inline const char *perf_reg_name(int id __maybe_unused)
16{ 18{
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0d1542f33d87..9a0a1839a377 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -628,11 +628,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
628 628
629 ret = debuginfo__find_line_range(dinfo, lr); 629 ret = debuginfo__find_line_range(dinfo, lr);
630 debuginfo__delete(dinfo); 630 debuginfo__delete(dinfo);
631 if (ret == 0) { 631 if (ret == 0 || ret == -ENOENT) {
632 pr_warning("Specified source line is not found.\n"); 632 pr_warning("Specified source line is not found.\n");
633 return -ENOENT; 633 return -ENOENT;
634 } else if (ret < 0) { 634 } else if (ret < 0) {
635 pr_warning("Debuginfo analysis failed. (%d)\n", ret); 635 pr_warning("Debuginfo analysis failed.\n");
636 return ret; 636 return ret;
637 } 637 }
638 638
@@ -641,7 +641,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
641 ret = get_real_path(tmp, lr->comp_dir, &lr->path); 641 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
642 free(tmp); /* Free old path */ 642 free(tmp); /* Free old path */
643 if (ret < 0) { 643 if (ret < 0) {
644 pr_warning("Failed to find source file. (%d)\n", ret); 644 pr_warning("Failed to find source file path.\n");
645 return ret; 645 return ret;
646 } 646 }
647 647
@@ -721,9 +721,14 @@ static int show_available_vars_at(struct debuginfo *dinfo,
721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
722 max_vls, externs); 722 max_vls, externs);
723 if (ret <= 0) { 723 if (ret <= 0) {
724 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 724 if (ret == 0 || ret == -ENOENT) {
725 pr_err("Failed to find the address of %s\n", buf);
726 ret = -ENOENT;
727 } else
728 pr_warning("Debuginfo analysis failed.\n");
725 goto end; 729 goto end;
726 } 730 }
731
727 /* Some variables are found */ 732 /* Some variables are found */
728 fprintf(stdout, "Available variables at %s\n", buf); 733 fprintf(stdout, "Available variables at %s\n", buf);
729 for (i = 0; i < ret; i++) { 734 for (i = 0; i < ret; i++) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 562762117639..98e304766416 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -511,12 +511,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
511 511
512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
513 &pf->sp_die, pf->tvar); 513 &pf->sp_die, pf->tvar);
514 if (ret == -ENOENT) 514 if (ret == -ENOENT || ret == -EINVAL)
515 pr_err("Failed to find the location of %s at this address.\n" 515 pr_err("Failed to find the location of %s at this address.\n"
516 " Perhaps, it has been optimized out.\n", pf->pvar->var); 516 " Perhaps, it has been optimized out.\n", pf->pvar->var);
517 else if (ret == -ENOTSUP) 517 else if (ret == -ENOTSUP)
518 pr_err("Sorry, we don't support this variable location yet.\n"); 518 pr_err("Sorry, we don't support this variable location yet.\n");
519 else if (pf->pvar->field) { 519 else if (ret == 0 && pf->pvar->field) {
520 ret = convert_variable_fields(vr_die, pf->pvar->var, 520 ret = convert_variable_fields(vr_die, pf->pvar->var,
521 pf->pvar->field, &pf->tvar->ref, 521 pf->pvar->field, &pf->tvar->ref,
522 &die_mem); 522 &die_mem);
@@ -573,14 +573,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
574 /* Search again in global variables */ 574 /* Search again in global variables */
575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
576 pr_warning("Failed to find '%s' in this function.\n",
577 pf->pvar->var);
576 ret = -ENOENT; 578 ret = -ENOENT;
577 } 579 }
578 if (ret >= 0) 580 if (ret >= 0)
579 ret = convert_variable(&vr_die, pf); 581 ret = convert_variable(&vr_die, pf);
580 582
581 if (ret < 0)
582 pr_warning("Failed to find '%s' in this function.\n",
583 pf->pvar->var);
584 return ret; 583 return ret;
585} 584}
586 585
@@ -1281,7 +1280,11 @@ out:
1281 return ret; 1280 return ret;
1282} 1281}
1283 1282
1284/* Find available variables at given probe point */ 1283/*
1284 * Find available variables at given probe point
1285 * Return the number of found probe points. Return 0 if there is no
1286 * matched probe point. Return <0 if an error occurs.
1287 */
1285int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1288int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1286 struct perf_probe_event *pev, 1289 struct perf_probe_event *pev,
1287 struct variable_list **vls, 1290 struct variable_list **vls,
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e108207c5de0..af7da565a750 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event,
215 case PRINT_BSTRING: 215 case PRINT_BSTRING:
216 case PRINT_DYNAMIC_ARRAY: 216 case PRINT_DYNAMIC_ARRAY:
217 case PRINT_STRING: 217 case PRINT_STRING:
218 case PRINT_BITMASK:
218 break; 219 break;
219 case PRINT_TYPE: 220 case PRINT_TYPE:
220 define_event_symbols(event, ev_name, args->typecast.item); 221 define_event_symbols(event, ev_name, args->typecast.item);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cd9774df3750..1c419321f707 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event,
197 case PRINT_BSTRING: 197 case PRINT_BSTRING:
198 case PRINT_DYNAMIC_ARRAY: 198 case PRINT_DYNAMIC_ARRAY:
199 case PRINT_FUNC: 199 case PRINT_FUNC:
200 case PRINT_BITMASK:
200 /* we should warn... */ 201 /* we should warn... */
201 return; 202 return;
202 } 203 }
@@ -622,6 +623,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
622 fprintf(ofp, "%s=", f->name); 623 fprintf(ofp, "%s=", f->name);
623 if (f->flags & FIELD_IS_STRING || 624 if (f->flags & FIELD_IS_STRING ||
624 f->flags & FIELD_IS_FLAG || 625 f->flags & FIELD_IS_FLAG ||
626 f->flags & FIELD_IS_ARRAY ||
625 f->flags & FIELD_IS_SYMBOLIC) 627 f->flags & FIELD_IS_SYMBOLIC)
626 fprintf(ofp, "%%s"); 628 fprintf(ofp, "%%s");
627 else if (f->flags & FIELD_IS_SIGNED) 629 else if (f->flags & FIELD_IS_SIGNED)
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 901b9bece2ee..1ec57dd82284 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,3 +1,4 @@
1#include <sys/mman.h>
1#include "sort.h" 2#include "sort.h"
2#include "hist.h" 3#include "hist.h"
3#include "comm.h" 4#include "comm.h"
@@ -784,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
784 return repsep_snprintf(bf, size, "%-*s", width, out); 785 return repsep_snprintf(bf, size, "%-*s", width, out);
785} 786}
786 787
788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
787struct sort_entry sort_mispredict = { 886struct sort_entry sort_mispredict = {
788 .se_header = "Branch Mispredicted", 887 .se_header = "Branch Mispredicted",
789 .se_cmp = sort__mispredict_cmp, 888 .se_cmp = sort__mispredict_cmp,
@@ -876,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
876 .se_width_idx = HISTC_MEM_SNOOP, 975 .se_width_idx = HISTC_MEM_SNOOP,
877}; 976};
878 977
978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
879static int64_t 985static int64_t
880sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
881{ 987{
@@ -1043,6 +1149,7 @@ static struct sort_dimension memory_sort_dimensions[] = {
1043 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1044 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1045 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1046}; 1153};
1047 1154
1048#undef DIM 1155#undef DIM
@@ -1061,6 +1168,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1064 DIM(PERF_HPP__SAMPLES, "sample"), 1172 DIM(PERF_HPP__SAMPLES, "sample"),
1065 DIM(PERF_HPP__PERIOD, "period"), 1173 DIM(PERF_HPP__PERIOD, "period"),
1066}; 1174};
@@ -1156,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1156 1264
1157 INIT_LIST_HEAD(&hse->hpp.list); 1265 INIT_LIST_HEAD(&hse->hpp.list);
1158 INIT_LIST_HEAD(&hse->hpp.sort_list); 1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false;
1159 1268
1160 return hse; 1269 return hse;
1161} 1270}
@@ -1363,27 +1472,64 @@ static int __setup_sorting(void)
1363 return ret; 1472 return ret;
1364} 1473}
1365 1474
1366bool perf_hpp__should_skip(struct perf_hpp_fmt *format) 1475void perf_hpp__set_elide(int idx, bool elide)
1367{ 1476{
1368 if (perf_hpp__is_sort_entry(format)) { 1477 struct perf_hpp_fmt *fmt;
1369 struct hpp_sort_entry *hse; 1478 struct hpp_sort_entry *hse;
1479
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1370 1483
1371 hse = container_of(format, struct hpp_sort_entry, hpp); 1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1372 return hse->se->elide; 1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
1373 } 1489 }
1374 return false;
1375} 1490}
1376 1491
1377static void sort_entry__setup_elide(struct sort_entry *se, 1492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1378 struct strlist *list,
1379 const char *list_name, FILE *fp)
1380{ 1493{
1381 if (list && strlist__nr_entries(list) == 1) { 1494 if (list && strlist__nr_entries(list) == 1) {
1382 if (fp != NULL) 1495 if (fp != NULL)
1383 fprintf(fp, "# %s: %s\n", list_name, 1496 fprintf(fp, "# %s: %s\n", list_name,
1384 strlist__entry(list, 0)->s); 1497 strlist__entry(list, 0)->s);
1385 se->elide = true; 1498 return true;
1386 } 1499 }
1500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1514 }
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
1387} 1533}
1388 1534
1389void sort__setup_elide(FILE *output) 1535void sort__setup_elide(FILE *output)
@@ -1391,39 +1537,12 @@ void sort__setup_elide(FILE *output)
1391 struct perf_hpp_fmt *fmt; 1537 struct perf_hpp_fmt *fmt;
1392 struct hpp_sort_entry *hse; 1538 struct hpp_sort_entry *hse;
1393 1539
1394 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1540 perf_hpp__for_each_format(fmt) {
1395 "dso", output); 1541 if (!perf_hpp__is_sort_entry(fmt))
1396 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, 1542 continue;
1397 "comm", output); 1543
1398 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, 1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1399 "symbol", output); 1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
1400
1401 if (sort__mode == SORT_MODE__BRANCH) {
1402 sort_entry__setup_elide(&sort_dso_from,
1403 symbol_conf.dso_from_list,
1404 "dso_from", output);
1405 sort_entry__setup_elide(&sort_dso_to,
1406 symbol_conf.dso_to_list,
1407 "dso_to", output);
1408 sort_entry__setup_elide(&sort_sym_from,
1409 symbol_conf.sym_from_list,
1410 "sym_from", output);
1411 sort_entry__setup_elide(&sort_sym_to,
1412 symbol_conf.sym_to_list,
1413 "sym_to", output);
1414 } else if (sort__mode == SORT_MODE__MEMORY) {
1415 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1416 "symbol_daddr", output);
1417 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1418 "dso_daddr", output);
1419 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1420 "mem", output);
1421 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1422 "local_weight", output);
1423 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1424 "tlb", output);
1425 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1426 "snoop", output);
1427 } 1546 }
1428 1547
1429 /* 1548 /*
@@ -1434,8 +1553,7 @@ void sort__setup_elide(FILE *output)
1434 if (!perf_hpp__is_sort_entry(fmt)) 1553 if (!perf_hpp__is_sort_entry(fmt))
1435 continue; 1554 continue;
1436 1555
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1556 if (!fmt->elide)
1438 if (!hse->se->elide)
1439 return; 1557 return;
1440 } 1558 }
1441 1559
@@ -1443,8 +1561,7 @@ void sort__setup_elide(FILE *output)
1443 if (!perf_hpp__is_sort_entry(fmt)) 1561 if (!perf_hpp__is_sort_entry(fmt))
1444 continue; 1562 continue;
1445 1563
1446 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1564 fmt->elide = false;
1447 hse->se->elide = false;
1448 } 1565 }
1449} 1566}
1450 1567
@@ -1581,6 +1698,9 @@ void reset_output_field(void)
1581 sort__has_sym = 0; 1698 sort__has_sym = 0;
1582 sort__has_dso = 0; 1699 sort__has_dso = 0;
1583 1700
1701 field_order = NULL;
1702 sort_order = NULL;
1703
1584 reset_dimensions(); 1704 reset_dimensions();
1585 perf_hpp__reset_output_field(); 1705 perf_hpp__reset_output_field();
1586} 1706}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5f38d925e92f..041f0c9cea2b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -20,7 +20,7 @@
20 20
21#include "parse-options.h" 21#include "parse-options.h"
22#include "parse-events.h" 22#include "parse-events.h"
23 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
@@ -82,12 +82,14 @@ struct hist_entry {
82 struct list_head head; 82 struct list_head head;
83 } pairs; 83 } pairs;
84 struct he_stat stat; 84 struct he_stat stat;
85 struct he_stat *stat_acc;
85 struct map_symbol ms; 86 struct map_symbol ms;
86 struct thread *thread; 87 struct thread *thread;
87 struct comm *comm; 88 struct comm *comm;
88 u64 ip; 89 u64 ip;
89 u64 transaction; 90 u64 transaction;
90 s32 cpu; 91 s32 cpu;
92 u8 cpumode;
91 93
92 struct hist_entry_diff diff; 94 struct hist_entry_diff diff;
93 95
@@ -130,6 +132,21 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,
130 list_add_tail(&pair->pairs.node, &he->pairs.head); 132 list_add_tail(&pair->pairs.node, &he->pairs.head);
131} 133}
132 134
135static inline float hist_entry__get_percent_limit(struct hist_entry *he)
136{
137 u64 period = he->stat.period;
138 u64 total_period = hists__total_period(he->hists);
139
140 if (unlikely(total_period == 0))
141 return 0;
142
143 if (symbol_conf.cumulate_callchain)
144 period = he->stat_acc->period;
145
146 return period * 100.0 / total_period;
147}
148
149
133enum sort_mode { 150enum sort_mode {
134 SORT_MODE__NORMAL, 151 SORT_MODE__NORMAL,
135 SORT_MODE__BRANCH, 152 SORT_MODE__BRANCH,
@@ -169,6 +186,7 @@ enum sort_type {
169 SORT_MEM_TLB, 186 SORT_MEM_TLB,
170 SORT_MEM_LVL, 187 SORT_MEM_LVL,
171 SORT_MEM_SNOOP, 188 SORT_MEM_SNOOP,
189 SORT_MEM_DCACHELINE,
172}; 190};
173 191
174/* 192/*
@@ -186,7 +204,6 @@ struct sort_entry {
186 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 204 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
187 unsigned int width); 205 unsigned int width);
188 u8 se_width_idx; 206 u8 se_width_idx;
189 bool elide;
190}; 207};
191 208
192extern struct sort_entry sort_thread; 209extern struct sort_entry sort_thread;
@@ -197,6 +214,7 @@ int setup_output_field(void);
197void reset_output_field(void); 214void reset_output_field(void);
198extern int sort_dimension__add(const char *); 215extern int sort_dimension__add(const char *);
199void sort__setup_elide(FILE *fp); 216void sort__setup_elide(FILE *fp);
217void perf_hpp__set_elide(int idx, bool elide);
200 218
201int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
202 220
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 95e249779931..7b9096f29cdb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;
29char **vmlinux_path; 29char **vmlinux_path;
30 30
31struct symbol_conf symbol_conf = { 31struct symbol_conf symbol_conf = {
32 .use_modules = true, 32 .use_modules = true,
33 .try_vmlinux_path = true, 33 .try_vmlinux_path = true,
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .symfs = "", 36 .cumulate_callchain = true,
37 .symfs = "",
37}; 38};
38 39
39static enum dso_binary_type binary_type_symtab[] = { 40static enum dso_binary_type binary_type_symtab[] = {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 33ede53fa6b9..615c752dd767 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -109,6 +109,7 @@ struct symbol_conf {
109 show_nr_samples, 109 show_nr_samples,
110 show_total_period, 110 show_total_period,
111 use_callchain, 111 use_callchain,
112 cumulate_callchain,
112 exclude_other, 113 exclude_other,
113 show_cpu_utilization, 114 show_cpu_utilization,
114 initialized, 115 initialized,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index bd5768d74f01..25578b98f5c5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -250,7 +250,6 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
250 250
251 /* Check the .eh_frame section for unwinding info */ 251 /* Check the .eh_frame section for unwinding info */
252 offset = elf_section_offset(fd, ".eh_frame_hdr"); 252 offset = elf_section_offset(fd, ".eh_frame_hdr");
253 close(fd);
254 253
255 if (offset) 254 if (offset)
256 ret = unwind_spec_ehframe(dso, machine, offset, 255 ret = unwind_spec_ehframe(dso, machine, offset,
@@ -271,7 +270,6 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
271 270
272 /* Check the .debug_frame section for unwinding info */ 271 /* Check the .debug_frame section for unwinding info */
273 *offset = elf_section_offset(fd, ".debug_frame"); 272 *offset = elf_section_offset(fd, ".debug_frame");
274 close(fd);
275 273
276 if (*offset) 274 if (*offset)
277 return 0; 275 return 0;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 7fff6be07f07..95aefa78bb07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,7 @@
17 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
18 */ 18 */
19unsigned int page_size; 19unsigned int page_size;
20int cacheline_size;
20 21
21bool test_attr__enabled; 22bool test_attr__enabled;
22 23
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b03da44e94e4..66864364ccb4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -304,6 +304,7 @@ char *rtrim(char *s);
304void dump_stack(void); 304void dump_stack(void);
305 305
306extern unsigned int page_size; 306extern unsigned int page_size;
307extern int cacheline_size;
307 308
308void get_term_dimensions(struct winsize *ws); 309void get_term_dimensions(struct winsize *ws);
309 310