aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-06-19 19:11:11 -0400
committerIngo Molnar <mingo@kernel.org>2015-06-19 19:11:11 -0400
commita9a3cd900fbbcbf837d65653105e7bfc583ced09 (patch)
treef59dd3c9d866c2fa8aa85b90c1eac83bf4f515a9 /tools
parent79928928c5a27d58ae48285d2a3f7aa835db7547 (diff)
parent9d9cad763ca79dd3697e9f2d1df648e37496582b (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Replace CTRL+z with 'f' as hotkey for enable/disable events (Arnaldo Carvalho de Melo) - Do not exit when 'f' is pressed in 'report' mode (Arnaldo Carvalho de Melo) - Tell the user how to unfreeze events after pressing 'f' in 'perf top' (Arnaldo Carvalho de Melo) - React to unassigned hotkey pressing in 'top/report' (Arnaldo Carvalho de Melo) - Display total number of samples with --show-total-period in 'annotate' (Martin Liška) - Add timeout to make procfs mmap processing more robust (Kan Liang) - Fix sort__sym_cmp to also compare end of symbol (Yannick Brosseau) Infrastructure changes: - Ensure thread-stack is flushed (Adrian Hunter) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-kvm.txt6
-rw-r--r--tools/perf/Documentation/perf-record.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt6
-rw-r--r--tools/perf/Documentation/perf-trace.txt5
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-kvm.c5
-rw-r--r--tools/perf/builtin-record.c6
-rw-r--r--tools/perf/builtin-top.c15
-rw-r--r--tools/perf/builtin-trace.c6
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c4
-rw-r--r--tools/perf/ui/browsers/annotate.c60
-rw-r--r--tools/perf/ui/browsers/hists.c15
-rw-r--r--tools/perf/util/annotate.c52
-rw-r--r--tools/perf/util/annotate.h7
-rw-r--r--tools/perf/util/event.c46
-rw-r--r--tools/perf/util/event.h10
-rw-r--r--tools/perf/util/machine.c28
-rw-r--r--tools/perf/util/machine.h12
-rw-r--r--tools/perf/util/session.c33
-rw-r--r--tools/perf/util/sort.c8
-rw-r--r--tools/perf/util/thread-stack.c18
-rw-r--r--tools/perf/util/thread-stack.h1
25 files changed, 274 insertions, 81 deletions
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 6252e776009c..6a5bb2b17039 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -151,6 +151,12 @@ STAT LIVE OPTIONS
151 Show events other than HLT (x86 only) or Wait state (s390 only) 151 Show events other than HLT (x86 only) or Wait state (s390 only)
152 that take longer than duration usecs. 152 that take longer than duration usecs.
153 153
154--proc-map-timeout::
155 When processing pre-existing threads /proc/XXX/mmap, it may take
156 a long time, because the file may be huge. A time out is needed
157 in such cases.
158 This option sets the time out limit. The default value is 500 ms.
159
154SEE ALSO 160SEE ALSO
155-------- 161--------
156linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], 162linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 6fdf78625c51..9b9d9d086680 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -271,6 +271,11 @@ AUX area tracing event. Optionally the number of bytes to capture per
271snapshot can be specified. In Snapshot Mode, trace data is captured only when 271snapshot can be specified. In Snapshot Mode, trace data is captured only when
272signal SIGUSR2 is received. 272signal SIGUSR2 is received.
273 273
274--proc-map-timeout::
275When processing pre-existing threads /proc/XXX/mmap, it may take a long time,
276because the file may be huge. A time out is needed in such cases.
277This option sets the time out limit. The default value is 500 ms.
278
274SEE ALSO 279SEE ALSO
275-------- 280--------
276linkperf:perf-stat[1], linkperf:perf-list[1] 281linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 9e5b07eb7d35..776aec4d0927 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -201,6 +201,12 @@ Default is to monitor all CPUS.
201 Force each column width to the provided list, for large terminal 201 Force each column width to the provided list, for large terminal
202 readability. 0 means no limit (default behavior). 202 readability. 0 means no limit (default behavior).
203 203
204--proc-map-timeout::
205 When processing pre-existing threads /proc/XXX/mmap, it may take
206 a long time, because the file may be huge. A time out is needed
207 in such cases.
208 This option sets the time out limit. The default value is 500 ms.
209
204 210
205INTERACTIVE PROMPTING KEYS 211INTERACTIVE PROMPTING KEYS
206-------------------------- 212--------------------------
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 1db9c8b79880..7ea078658a87 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -121,6 +121,11 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
121--event:: 121--event::
122 Trace other events, see 'perf list' for a complete list. 122 Trace other events, see 'perf list' for a complete list.
123 123
124--proc-map-timeout::
125 When processing pre-existing threads /proc/XXX/mmap, it may take a long time,
126 because the file may be huge. A time out is needed in such cases.
127 This option sets the time out limit. The default value is 500 ms.
128
124PAGEFAULTS 129PAGEFAULTS
125---------- 130----------
126 131
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4e08c2d2090e..2c1bec39c30e 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -329,6 +329,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
329 "objdump binary to use for disassembly and annotations"), 329 "objdump binary to use for disassembly and annotations"),
330 OPT_BOOLEAN(0, "group", &symbol_conf.event_group, 330 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
331 "Show event group information together"), 331 "Show event group information together"),
332 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
333 "Show a column with the sum of periods"),
332 OPT_END() 334 OPT_END()
333 }; 335 };
334 int ret = hists__init(); 336 int ret = hists__init();
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 15fecd3dc5d8..74878cd75078 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1311,6 +1311,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1311 "show events other than" 1311 "show events other than"
1312 " HLT (x86 only) or Wait state (s390 only)" 1312 " HLT (x86 only) or Wait state (s390 only)"
1313 " that take longer than duration usecs"), 1313 " that take longer than duration usecs"),
1314 OPT_UINTEGER(0, "proc-map-timeout", &kvm->opts.proc_map_timeout,
1315 "per thread proc mmap processing timeout in ms"),
1314 OPT_END() 1316 OPT_END()
1315 }; 1317 };
1316 const char * const live_usage[] = { 1318 const char * const live_usage[] = {
@@ -1338,6 +1340,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1338 kvm->opts.target.uses_mmap = false; 1340 kvm->opts.target.uses_mmap = false;
1339 kvm->opts.target.uid_str = NULL; 1341 kvm->opts.target.uid_str = NULL;
1340 kvm->opts.target.uid = UINT_MAX; 1342 kvm->opts.target.uid = UINT_MAX;
1343 kvm->opts.proc_map_timeout = 500;
1341 1344
1342 symbol__init(NULL); 1345 symbol__init(NULL);
1343 disable_buildid_cache(); 1346 disable_buildid_cache();
@@ -1393,7 +1396,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1393 perf_session__set_id_hdr_size(kvm->session); 1396 perf_session__set_id_hdr_size(kvm->session);
1394 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); 1397 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);
1395 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, 1398 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
1396 kvm->evlist->threads, false); 1399 kvm->evlist->threads, false, kvm->opts.proc_map_timeout);
1397 err = kvm_live_open_events(kvm); 1400 err = kvm_live_open_events(kvm);
1398 if (err) 1401 if (err)
1399 goto out; 1402 goto out;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4d6cdeb94fe1..de165a1b9240 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -598,7 +598,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
598 } 598 }
599 599
600 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 600 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
601 process_synthesized_event, opts->sample_address); 601 process_synthesized_event, opts->sample_address,
602 opts->proc_map_timeout);
602 if (err != 0) 603 if (err != 0)
603 goto out_child; 604 goto out_child;
604 605
@@ -959,6 +960,7 @@ static struct record record = {
959 .uses_mmap = true, 960 .uses_mmap = true,
960 .default_per_cpu = true, 961 .default_per_cpu = true,
961 }, 962 },
963 .proc_map_timeout = 500,
962 }, 964 },
963 .tool = { 965 .tool = {
964 .sample = process_sample_event, 966 .sample = process_sample_event,
@@ -1066,6 +1068,8 @@ struct option __record_options[] = {
1066 parse_clockid), 1068 parse_clockid),
1067 OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts, 1069 OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
1068 "opts", "AUX area tracing Snapshot Mode", ""), 1070 "opts", "AUX area tracing Snapshot Mode", ""),
1071 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
1072 "per thread proc mmap processing timeout in ms"),
1069 OPT_END() 1073 OPT_END()
1070}; 1074};
1071 1075
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 72d8a7ae5986..619a8696fda7 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -591,7 +591,7 @@ static void *display_thread_tui(void *arg)
591 top->min_percent, 591 top->min_percent,
592 &top->session->header.env); 592 &top->session->header.env);
593 593
594 if (key != CTRL('z')) 594 if (key != 'f')
595 break; 595 break;
596 596
597 perf_evlist__toggle_enable(top->evlist); 597 perf_evlist__toggle_enable(top->evlist);
@@ -599,7 +599,13 @@ static void *display_thread_tui(void *arg)
599 * No need to refresh, resort/decay histogram entries 599 * No need to refresh, resort/decay histogram entries
600 * if we are not collecting samples: 600 * if we are not collecting samples:
601 */ 601 */
602 hbt.refresh = top->evlist->enabled ? top->delay_secs : 0; 602 if (top->evlist->enabled) {
603 hbt.refresh = top->delay_secs;
604 help = "Press 'f' to disable the events or 'h' to see other hotkeys";
605 } else {
606 help = "Press 'f' again to re-enable the events";
607 hbt.refresh = 0;
608 }
603 } 609 }
604 610
605 done = 1; 611 done = 1;
@@ -971,7 +977,7 @@ static int __cmd_top(struct perf_top *top)
971 goto out_delete; 977 goto out_delete;
972 978
973 machine__synthesize_threads(&top->session->machines.host, &opts->target, 979 machine__synthesize_threads(&top->session->machines.host, &opts->target,
974 top->evlist->threads, false); 980 top->evlist->threads, false, opts->proc_map_timeout);
975 ret = perf_top__start_counters(top); 981 ret = perf_top__start_counters(top);
976 if (ret) 982 if (ret)
977 goto out_delete; 983 goto out_delete;
@@ -1081,6 +1087,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1081 .target = { 1087 .target = {
1082 .uses_mmap = true, 1088 .uses_mmap = true,
1083 }, 1089 },
1090 .proc_map_timeout = 500,
1084 }, 1091 },
1085 .max_stack = PERF_MAX_STACK_DEPTH, 1092 .max_stack = PERF_MAX_STACK_DEPTH,
1086 .sym_pcnt_filter = 5, 1093 .sym_pcnt_filter = 5,
@@ -1180,6 +1187,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1180 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, 1187 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1181 "width[,width...]", 1188 "width[,width...]",
1182 "don't try to adjust column width, use these fixed values"), 1189 "don't try to adjust column width, use these fixed values"),
1190 OPT_UINTEGER(0, "proc-map-timeout", &opts->proc_map_timeout,
1191 "per thread proc mmap processing timeout in ms"),
1183 OPT_END() 1192 OPT_END()
1184 }; 1193 };
1185 const char * const top_usage[] = { 1194 const char * const top_usage[] = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 4bf805b2fbf6..de5d277d1ad7 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1518,7 +1518,8 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1518 return -ENOMEM; 1518 return -ENOMEM;
1519 1519
1520 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, 1520 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1521 evlist->threads, trace__tool_process, false); 1521 evlist->threads, trace__tool_process, false,
1522 trace->opts.proc_map_timeout);
1522 if (err) 1523 if (err)
1523 symbol__exit(); 1524 symbol__exit();
1524 1525
@@ -2747,6 +2748,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2747 .user_interval = ULLONG_MAX, 2748 .user_interval = ULLONG_MAX,
2748 .no_buffering = true, 2749 .no_buffering = true,
2749 .mmap_pages = UINT_MAX, 2750 .mmap_pages = UINT_MAX,
2751 .proc_map_timeout = 500,
2750 }, 2752 },
2751 .output = stdout, 2753 .output = stdout,
2752 .show_comm = true, 2754 .show_comm = true,
@@ -2796,6 +2798,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2796 "Trace pagefaults", parse_pagefaults, "maj"), 2798 "Trace pagefaults", parse_pagefaults, "maj"),
2797 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), 2799 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
2798 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), 2800 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
2801 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2802 "per thread proc mmap processing timeout in ms"),
2799 OPT_END() 2803 OPT_END()
2800 }; 2804 };
2801 const char * const trace_subcommands[] = { "record", NULL }; 2805 const char * const trace_subcommands[] = { "record", NULL };
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index aa79fb8a16d4..4a5827fff799 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -69,6 +69,7 @@ struct record_opts {
69 unsigned initial_delay; 69 unsigned initial_delay;
70 bool use_clockid; 70 bool use_clockid;
71 clockid_t clockid; 71 clockid_t clockid;
72 unsigned int proc_map_timeout;
72}; 73};
73 74
74struct option; 75struct option;
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index e2a432b67d52..22f8a00446e1 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -451,7 +451,7 @@ static int do_test_code_reading(bool try_kcore)
451 } 451 }
452 452
453 ret = perf_event__synthesize_thread_map(NULL, threads, 453 ret = perf_event__synthesize_thread_map(NULL, threads,
454 perf_event__process, machine, false); 454 perf_event__process, machine, false, 500);
455 if (ret < 0) { 455 if (ret < 0) {
456 pr_debug("perf_event__synthesize_thread_map failed\n"); 456 pr_debug("perf_event__synthesize_thread_map failed\n");
457 goto out_err; 457 goto out_err;
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 9b748e1ad46e..40b36c462427 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -28,7 +28,7 @@ static int init_live_machine(struct machine *machine)
28 pid_t pid = getpid(); 28 pid_t pid = getpid();
29 29
30 return perf_event__synthesize_mmap_events(NULL, &event, pid, pid, 30 return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
31 mmap_handler, machine, true); 31 mmap_handler, machine, true, 500);
32} 32}
33 33
34#define MAX_STACK 8 34#define MAX_STACK 8
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 264e215c0d36..7f48efa7e295 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -129,7 +129,7 @@ static int synth_all(struct machine *machine)
129{ 129{
130 return perf_event__synthesize_threads(NULL, 130 return perf_event__synthesize_threads(NULL,
131 perf_event__process, 131 perf_event__process,
132 machine, 0); 132 machine, 0, 500);
133} 133}
134 134
135static int synth_process(struct machine *machine) 135static int synth_process(struct machine *machine)
@@ -141,7 +141,7 @@ static int synth_process(struct machine *machine)
141 141
142 err = perf_event__synthesize_thread_map(NULL, map, 142 err = perf_event__synthesize_thread_map(NULL, map,
143 perf_event__process, 143 perf_event__process,
144 machine, 0); 144 machine, 0, 500);
145 145
146 thread_map__delete(map); 146 thread_map__delete(map);
147 return err; 147 return err;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index acb0e23b138e..5995a8bd7c69 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -11,16 +11,21 @@
11#include "../../util/evsel.h" 11#include "../../util/evsel.h"
12#include <pthread.h> 12#include <pthread.h>
13 13
14struct disasm_line_samples {
15 double percent;
16 u64 nr;
17};
18
14struct browser_disasm_line { 19struct browser_disasm_line {
15 struct rb_node rb_node; 20 struct rb_node rb_node;
16 u32 idx; 21 u32 idx;
17 int idx_asm; 22 int idx_asm;
18 int jump_sources; 23 int jump_sources;
19 /* 24 /*
20 * actual length of this array is saved on the nr_events field 25 * actual length of this array is saved on the nr_events field
21 * of the struct annotate_browser 26 * of the struct annotate_browser
22 */ 27 */
23 double percent[1]; 28 struct disasm_line_samples samples[1];
24}; 29};
25 30
26static struct annotate_browser_opt { 31static struct annotate_browser_opt {
@@ -28,7 +33,8 @@ static struct annotate_browser_opt {
28 use_offset, 33 use_offset,
29 jump_arrows, 34 jump_arrows,
30 show_linenr, 35 show_linenr,
31 show_nr_jumps; 36 show_nr_jumps,
37 show_total_period;
32} annotate_browser__opts = { 38} annotate_browser__opts = {
33 .use_offset = true, 39 .use_offset = true,
34 .jump_arrows = true, 40 .jump_arrows = true,
@@ -105,15 +111,20 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
105 char bf[256]; 111 char bf[256];
106 112
107 for (i = 0; i < ab->nr_events; i++) { 113 for (i = 0; i < ab->nr_events; i++) {
108 if (bdl->percent[i] > percent_max) 114 if (bdl->samples[i].percent > percent_max)
109 percent_max = bdl->percent[i]; 115 percent_max = bdl->samples[i].percent;
110 } 116 }
111 117
112 if (dl->offset != -1 && percent_max != 0.0) { 118 if (dl->offset != -1 && percent_max != 0.0) {
113 for (i = 0; i < ab->nr_events; i++) { 119 for (i = 0; i < ab->nr_events; i++) {
114 ui_browser__set_percent_color(browser, bdl->percent[i], 120 ui_browser__set_percent_color(browser,
121 bdl->samples[i].percent,
115 current_entry); 122 current_entry);
116 slsmg_printf("%6.2f ", bdl->percent[i]); 123 if (annotate_browser__opts.show_total_period)
124 slsmg_printf("%6" PRIu64 " ",
125 bdl->samples[i].nr);
126 else
127 slsmg_printf("%6.2f ", bdl->samples[i].percent);
117 } 128 }
118 } else { 129 } else {
119 ui_browser__set_percent_color(browser, 0, current_entry); 130 ui_browser__set_percent_color(browser, 0, current_entry);
@@ -273,9 +284,9 @@ static int disasm__cmp(struct browser_disasm_line *a,
273 int i; 284 int i;
274 285
275 for (i = 0; i < nr_pcnt; i++) { 286 for (i = 0; i < nr_pcnt; i++) {
276 if (a->percent[i] == b->percent[i]) 287 if (a->samples[i].percent == b->samples[i].percent)
277 continue; 288 continue;
278 return a->percent[i] < b->percent[i]; 289 return a->samples[i].percent < b->samples[i].percent;
279 } 290 }
280 return 0; 291 return 0;
281} 292}
@@ -366,14 +377,17 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
366 next = disasm__get_next_ip_line(&notes->src->source, pos); 377 next = disasm__get_next_ip_line(&notes->src->source, pos);
367 378
368 for (i = 0; i < browser->nr_events; i++) { 379 for (i = 0; i < browser->nr_events; i++) {
369 bpos->percent[i] = disasm__calc_percent(notes, 380 u64 nr_samples;
381
382 bpos->samples[i].percent = disasm__calc_percent(notes,
370 evsel->idx + i, 383 evsel->idx + i,
371 pos->offset, 384 pos->offset,
372 next ? next->offset : len, 385 next ? next->offset : len,
373 &path); 386 &path, &nr_samples);
387 bpos->samples[i].nr = nr_samples;
374 388
375 if (max_percent < bpos->percent[i]) 389 if (max_percent < bpos->samples[i].percent)
376 max_percent = bpos->percent[i]; 390 max_percent = bpos->samples[i].percent;
377 } 391 }
378 392
379 if (max_percent < 0.01) { 393 if (max_percent < 0.01) {
@@ -737,6 +751,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
737 "n Search next string\n" 751 "n Search next string\n"
738 "o Toggle disassembler output/simplified view\n" 752 "o Toggle disassembler output/simplified view\n"
739 "s Toggle source code view\n" 753 "s Toggle source code view\n"
754 "t Toggle total period view\n"
740 "/ Search string\n" 755 "/ Search string\n"
741 "k Toggle line numbers\n" 756 "k Toggle line numbers\n"
742 "r Run available scripts\n" 757 "r Run available scripts\n"
@@ -812,6 +827,11 @@ show_sup_ins:
812 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 827 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
813 } 828 }
814 continue; 829 continue;
830 case 't':
831 annotate_browser__opts.show_total_period =
832 !annotate_browser__opts.show_total_period;
833 annotate_browser__update_addr_width(browser);
834 continue;
815 case K_LEFT: 835 case K_LEFT:
816 case K_ESC: 836 case K_ESC:
817 case 'q': 837 case 'q':
@@ -832,6 +852,10 @@ out:
832int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 852int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
833 struct hist_browser_timer *hbt) 853 struct hist_browser_timer *hbt)
834{ 854{
855 /* Set default value for show_total_period. */
856 annotate_browser__opts.show_total_period =
857 symbol_conf.show_total_period;
858
835 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); 859 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
836} 860}
837 861
@@ -929,7 +953,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
929 953
930 if (perf_evsel__is_group_event(evsel)) { 954 if (perf_evsel__is_group_event(evsel)) {
931 nr_pcnt = evsel->nr_members; 955 nr_pcnt = evsel->nr_members;
932 sizeof_bdl += sizeof(double) * (nr_pcnt - 1); 956 sizeof_bdl += sizeof(struct disasm_line_samples) *
957 (nr_pcnt - 1);
933 } 958 }
934 959
935 if (symbol__annotate(sym, map, sizeof_bdl) < 0) { 960 if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
@@ -1006,6 +1031,7 @@ static struct annotate_config {
1006 ANNOTATE_CFG(show_linenr), 1031 ANNOTATE_CFG(show_linenr),
1007 ANNOTATE_CFG(show_nr_jumps), 1032 ANNOTATE_CFG(show_nr_jumps),
1008 ANNOTATE_CFG(use_offset), 1033 ANNOTATE_CFG(use_offset),
1034 ANNOTATE_CFG(show_total_period),
1009}; 1035};
1010 1036
1011#undef ANNOTATE_CFG 1037#undef ANNOTATE_CFG
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 8f7c4d49d327..c42adb600091 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -424,7 +424,7 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
424 "Or reduce the sampling frequency."); 424 "Or reduce the sampling frequency.");
425} 425}
426 426
427static int hist_browser__run(struct hist_browser *browser) 427static int hist_browser__run(struct hist_browser *browser, const char *help)
428{ 428{
429 int key; 429 int key;
430 char title[160]; 430 char title[160];
@@ -436,8 +436,7 @@ static int hist_browser__run(struct hist_browser *browser)
436 436
437 hists__browser_title(browser->hists, hbt, title, sizeof(title)); 437 hists__browser_title(browser->hists, hbt, title, sizeof(title));
438 438
439 if (ui_browser__show(&browser->b, title, 439 if (ui_browser__show(&browser->b, title, help) < 0)
440 "Press '?' for help on key bindings") < 0)
441 return -1; 440 return -1;
442 441
443 while (1) { 442 while (1) {
@@ -1736,7 +1735,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1736 "t Zoom into current Thread\n" 1735 "t Zoom into current Thread\n"
1737 "V Verbose (DSO names in callchains, etc)\n" 1736 "V Verbose (DSO names in callchains, etc)\n"
1738 "z Toggle zeroing of samples\n" 1737 "z Toggle zeroing of samples\n"
1739 "CTRL+z Enable/Disable events\n" 1738 "f Enable/Disable events\n"
1740 "/ Filter symbol by name"; 1739 "/ Filter symbol by name";
1741 1740
1742 if (browser == NULL) 1741 if (browser == NULL)
@@ -1773,7 +1772,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1773 1772
1774 nr_options = 0; 1773 nr_options = 0;
1775 1774
1776 key = hist_browser__run(browser); 1775 key = hist_browser__run(browser, helpline);
1777 1776
1778 if (browser->he_selection != NULL) { 1777 if (browser->he_selection != NULL) {
1779 thread = hist_browser__selected_thread(browser); 1778 thread = hist_browser__selected_thread(browser);
@@ -1901,9 +1900,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1901 /* Fall thru */ 1900 /* Fall thru */
1902 case 'q': 1901 case 'q':
1903 case CTRL('c'): 1902 case CTRL('c'):
1904 case CTRL('z'):
1905 goto out_free_stack; 1903 goto out_free_stack;
1904 case 'f':
1905 if (!is_report_browser(hbt))
1906 goto out_free_stack;
1907 /* Fall thru */
1906 default: 1908 default:
1909 helpline = "Press '?' for help on key bindings";
1907 continue; 1910 continue;
1908 } 1911 }
1909 1912
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index bf8043009909..03b7bc70eb66 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -654,14 +654,15 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
654} 654}
655 655
656double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, 656double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
657 s64 end, const char **path) 657 s64 end, const char **path, u64 *nr_samples)
658{ 658{
659 struct source_line *src_line = notes->src->lines; 659 struct source_line *src_line = notes->src->lines;
660 double percent = 0.0; 660 double percent = 0.0;
661 *nr_samples = 0;
661 662
662 if (src_line) { 663 if (src_line) {
663 size_t sizeof_src_line = sizeof(*src_line) + 664 size_t sizeof_src_line = sizeof(*src_line) +
664 sizeof(src_line->p) * (src_line->nr_pcnt - 1); 665 sizeof(src_line->samples) * (src_line->nr_pcnt - 1);
665 666
666 while (offset < end) { 667 while (offset < end) {
667 src_line = (void *)notes->src->lines + 668 src_line = (void *)notes->src->lines +
@@ -670,7 +671,8 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
670 if (*path == NULL) 671 if (*path == NULL)
671 *path = src_line->path; 672 *path = src_line->path;
672 673
673 percent += src_line->p[evidx].percent; 674 percent += src_line->samples[evidx].percent;
675 *nr_samples += src_line->samples[evidx].nr;
674 offset++; 676 offset++;
675 } 677 }
676 } else { 678 } else {
@@ -680,8 +682,10 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
680 while (offset < end) 682 while (offset < end)
681 hits += h->addr[offset++]; 683 hits += h->addr[offset++];
682 684
683 if (h->sum) 685 if (h->sum) {
686 *nr_samples = hits;
684 percent = 100.0 * hits / h->sum; 687 percent = 100.0 * hits / h->sum;
688 }
685 } 689 }
686 690
687 return percent; 691 return percent;
@@ -696,8 +700,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
696 700
697 if (dl->offset != -1) { 701 if (dl->offset != -1) {
698 const char *path = NULL; 702 const char *path = NULL;
703 u64 nr_samples;
699 double percent, max_percent = 0.0; 704 double percent, max_percent = 0.0;
700 double *ppercents = &percent; 705 double *ppercents = &percent;
706 u64 *psamples = &nr_samples;
701 int i, nr_percent = 1; 707 int i, nr_percent = 1;
702 const char *color; 708 const char *color;
703 struct annotation *notes = symbol__annotation(sym); 709 struct annotation *notes = symbol__annotation(sym);
@@ -710,8 +716,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
710 if (perf_evsel__is_group_event(evsel)) { 716 if (perf_evsel__is_group_event(evsel)) {
711 nr_percent = evsel->nr_members; 717 nr_percent = evsel->nr_members;
712 ppercents = calloc(nr_percent, sizeof(double)); 718 ppercents = calloc(nr_percent, sizeof(double));
713 if (ppercents == NULL) 719 psamples = calloc(nr_percent, sizeof(u64));
720 if (ppercents == NULL || psamples == NULL) {
714 return -1; 721 return -1;
722 }
715 } 723 }
716 724
717 for (i = 0; i < nr_percent; i++) { 725 for (i = 0; i < nr_percent; i++) {
@@ -719,9 +727,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
719 notes->src->lines ? i : evsel->idx + i, 727 notes->src->lines ? i : evsel->idx + i,
720 offset, 728 offset,
721 next ? next->offset : (s64) len, 729 next ? next->offset : (s64) len,
722 &path); 730 &path, &nr_samples);
723 731
724 ppercents[i] = percent; 732 ppercents[i] = percent;
733 psamples[i] = nr_samples;
725 if (percent > max_percent) 734 if (percent > max_percent)
726 max_percent = percent; 735 max_percent = percent;
727 } 736 }
@@ -759,8 +768,14 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
759 768
760 for (i = 0; i < nr_percent; i++) { 769 for (i = 0; i < nr_percent; i++) {
761 percent = ppercents[i]; 770 percent = ppercents[i];
771 nr_samples = psamples[i];
762 color = get_percent_color(percent); 772 color = get_percent_color(percent);
763 color_fprintf(stdout, color, " %7.2f", percent); 773
774 if (symbol_conf.show_total_period)
775 color_fprintf(stdout, color, " %7" PRIu64,
776 nr_samples);
777 else
778 color_fprintf(stdout, color, " %7.2f", percent);
764 } 779 }
765 780
766 printf(" : "); 781 printf(" : ");
@@ -770,6 +785,9 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
770 if (ppercents != &percent) 785 if (ppercents != &percent)
771 free(ppercents); 786 free(ppercents);
772 787
788 if (psamples != &nr_samples)
789 free(psamples);
790
773 } else if (max_lines && printed >= max_lines) 791 } else if (max_lines && printed >= max_lines)
774 return 1; 792 return 1;
775 else { 793 else {
@@ -1103,7 +1121,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
1103 ret = strcmp(iter->path, src_line->path); 1121 ret = strcmp(iter->path, src_line->path);
1104 if (ret == 0) { 1122 if (ret == 0) {
1105 for (i = 0; i < src_line->nr_pcnt; i++) 1123 for (i = 0; i < src_line->nr_pcnt; i++)
1106 iter->p[i].percent_sum += src_line->p[i].percent; 1124 iter->samples[i].percent_sum += src_line->samples[i].percent;
1107 return; 1125 return;
1108 } 1126 }
1109 1127
@@ -1114,7 +1132,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
1114 } 1132 }
1115 1133
1116 for (i = 0; i < src_line->nr_pcnt; i++) 1134 for (i = 0; i < src_line->nr_pcnt; i++)
1117 src_line->p[i].percent_sum = src_line->p[i].percent; 1135 src_line->samples[i].percent_sum = src_line->samples[i].percent;
1118 1136
1119 rb_link_node(&src_line->node, parent, p); 1137 rb_link_node(&src_line->node, parent, p);
1120 rb_insert_color(&src_line->node, root); 1138 rb_insert_color(&src_line->node, root);
@@ -1125,9 +1143,9 @@ static int cmp_source_line(struct source_line *a, struct source_line *b)
1125 int i; 1143 int i;
1126 1144
1127 for (i = 0; i < a->nr_pcnt; i++) { 1145 for (i = 0; i < a->nr_pcnt; i++) {
1128 if (a->p[i].percent_sum == b->p[i].percent_sum) 1146 if (a->samples[i].percent_sum == b->samples[i].percent_sum)
1129 continue; 1147 continue;
1130 return a->p[i].percent_sum > b->p[i].percent_sum; 1148 return a->samples[i].percent_sum > b->samples[i].percent_sum;
1131 } 1149 }
1132 1150
1133 return 0; 1151 return 0;
@@ -1179,7 +1197,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1179 int i; 1197 int i;
1180 1198
1181 sizeof_src_line = sizeof(*src_line) + 1199 sizeof_src_line = sizeof(*src_line) +
1182 (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); 1200 (sizeof(src_line->samples) * (src_line->nr_pcnt - 1));
1183 1201
1184 for (i = 0; i < len; i++) { 1202 for (i = 0; i < len; i++) {
1185 free_srcline(src_line->path); 1203 free_srcline(src_line->path);
@@ -1211,7 +1229,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1211 h_sum += h->sum; 1229 h_sum += h->sum;
1212 } 1230 }
1213 nr_pcnt = evsel->nr_members; 1231 nr_pcnt = evsel->nr_members;
1214 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); 1232 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples);
1215 } 1233 }
1216 1234
1217 if (!h_sum) 1235 if (!h_sum)
@@ -1231,10 +1249,10 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1231 1249
1232 for (k = 0; k < nr_pcnt; k++) { 1250 for (k = 0; k < nr_pcnt; k++) {
1233 h = annotation__histogram(notes, evidx + k); 1251 h = annotation__histogram(notes, evidx + k);
1234 src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; 1252 src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum;
1235 1253
1236 if (src_line->p[k].percent > percent_max) 1254 if (src_line->samples[k].percent > percent_max)
1237 percent_max = src_line->p[k].percent; 1255 percent_max = src_line->samples[k].percent;
1238 } 1256 }
1239 1257
1240 if (percent_max <= 0.5) 1258 if (percent_max <= 0.5)
@@ -1274,7 +1292,7 @@ static void print_summary(struct rb_root *root, const char *filename)
1274 1292
1275 src_line = rb_entry(node, struct source_line, node); 1293 src_line = rb_entry(node, struct source_line, node);
1276 for (i = 0; i < src_line->nr_pcnt; i++) { 1294 for (i = 0; i < src_line->nr_pcnt; i++) {
1277 percent = src_line->p[i].percent_sum; 1295 percent = src_line->samples[i].percent_sum;
1278 color = get_percent_color(percent); 1296 color = get_percent_color(percent);
1279 color_fprintf(stdout, color, " %7.2f", percent); 1297 color_fprintf(stdout, color, " %7.2f", percent);
1280 1298
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index cadbdc90a5cb..7e78e6c27078 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -72,23 +72,24 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
72int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 72int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
73size_t disasm__fprintf(struct list_head *head, FILE *fp); 73size_t disasm__fprintf(struct list_head *head, FILE *fp);
74double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, 74double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
75 s64 end, const char **path); 75 s64 end, const char **path, u64 *nr_samples);
76 76
77struct sym_hist { 77struct sym_hist {
78 u64 sum; 78 u64 sum;
79 u64 addr[0]; 79 u64 addr[0];
80}; 80};
81 81
82struct source_line_percent { 82struct source_line_samples {
83 double percent; 83 double percent;
84 double percent_sum; 84 double percent_sum;
85 double nr;
85}; 86};
86 87
87struct source_line { 88struct source_line {
88 struct rb_node node; 89 struct rb_node node;
89 char *path; 90 char *path;
90 int nr_pcnt; 91 int nr_pcnt;
91 struct source_line_percent p[1]; 92 struct source_line_samples samples[1];
92}; 93};
93 94
94/** struct annotated_source - symbols with hits have this attached as in sannotation 95/** struct annotated_source - symbols with hits have this attached as in sannotation
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 793b1503d437..d7d986d8f23e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -218,10 +218,14 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
218 pid_t pid, pid_t tgid, 218 pid_t pid, pid_t tgid,
219 perf_event__handler_t process, 219 perf_event__handler_t process,
220 struct machine *machine, 220 struct machine *machine,
221 bool mmap_data) 221 bool mmap_data,
222 unsigned int proc_map_timeout)
222{ 223{
223 char filename[PATH_MAX]; 224 char filename[PATH_MAX];
224 FILE *fp; 225 FILE *fp;
226 unsigned long long t;
227 bool truncation = false;
228 unsigned long long timeout = proc_map_timeout * 1000000ULL;
225 int rc = 0; 229 int rc = 0;
226 230
227 if (machine__is_default_guest(machine)) 231 if (machine__is_default_guest(machine))
@@ -240,6 +244,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
240 } 244 }
241 245
242 event->header.type = PERF_RECORD_MMAP2; 246 event->header.type = PERF_RECORD_MMAP2;
247 t = rdclock();
243 248
244 while (1) { 249 while (1) {
245 char bf[BUFSIZ]; 250 char bf[BUFSIZ];
@@ -253,6 +258,15 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
253 if (fgets(bf, sizeof(bf), fp) == NULL) 258 if (fgets(bf, sizeof(bf), fp) == NULL)
254 break; 259 break;
255 260
261 if ((rdclock() - t) > timeout) {
262 pr_warning("Reading %s time out. "
263 "You may want to increase "
264 "the time limit by --proc-map-timeout\n",
265 filename);
266 truncation = true;
267 goto out;
268 }
269
256 /* ensure null termination since stack will be reused. */ 270 /* ensure null termination since stack will be reused. */
257 strcpy(execname, ""); 271 strcpy(execname, "");
258 272
@@ -301,6 +315,10 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
301 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 315 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
302 } 316 }
303 317
318out:
319 if (truncation)
320 event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT;
321
304 if (!strcmp(execname, "")) 322 if (!strcmp(execname, ""))
305 strcpy(execname, anonstr); 323 strcpy(execname, anonstr);
306 324
@@ -319,6 +337,9 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
319 rc = -1; 337 rc = -1;
320 break; 338 break;
321 } 339 }
340
341 if (truncation)
342 break;
322 } 343 }
323 344
324 fclose(fp); 345 fclose(fp);
@@ -386,7 +407,9 @@ static int __event__synthesize_thread(union perf_event *comm_event,
386 pid_t pid, int full, 407 pid_t pid, int full,
387 perf_event__handler_t process, 408 perf_event__handler_t process,
388 struct perf_tool *tool, 409 struct perf_tool *tool,
389 struct machine *machine, bool mmap_data) 410 struct machine *machine,
411 bool mmap_data,
412 unsigned int proc_map_timeout)
390{ 413{
391 char filename[PATH_MAX]; 414 char filename[PATH_MAX];
392 DIR *tasks; 415 DIR *tasks;
@@ -403,7 +426,8 @@ static int __event__synthesize_thread(union perf_event *comm_event,
403 return -1; 426 return -1;
404 427
405 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 428 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
406 process, machine, mmap_data); 429 process, machine, mmap_data,
430 proc_map_timeout);
407 } 431 }
408 432
409 if (machine__is_default_guest(machine)) 433 if (machine__is_default_guest(machine))
@@ -444,7 +468,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
444 if (_pid == pid) { 468 if (_pid == pid) {
445 /* process the parent's maps too */ 469 /* process the parent's maps too */
446 rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 470 rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
447 process, machine, mmap_data); 471 process, machine, mmap_data, proc_map_timeout);
448 if (rc) 472 if (rc)
449 break; 473 break;
450 } 474 }
@@ -458,7 +482,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
458 struct thread_map *threads, 482 struct thread_map *threads,
459 perf_event__handler_t process, 483 perf_event__handler_t process,
460 struct machine *machine, 484 struct machine *machine,
461 bool mmap_data) 485 bool mmap_data,
486 unsigned int proc_map_timeout)
462{ 487{
463 union perf_event *comm_event, *mmap_event, *fork_event; 488 union perf_event *comm_event, *mmap_event, *fork_event;
464 int err = -1, thread, j; 489 int err = -1, thread, j;
@@ -481,7 +506,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
481 fork_event, 506 fork_event,
482 threads->map[thread], 0, 507 threads->map[thread], 0,
483 process, tool, machine, 508 process, tool, machine,
484 mmap_data)) { 509 mmap_data, proc_map_timeout)) {
485 err = -1; 510 err = -1;
486 break; 511 break;
487 } 512 }
@@ -507,7 +532,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
507 fork_event, 532 fork_event,
508 comm_event->comm.pid, 0, 533 comm_event->comm.pid, 0,
509 process, tool, machine, 534 process, tool, machine,
510 mmap_data)) { 535 mmap_data, proc_map_timeout)) {
511 err = -1; 536 err = -1;
512 break; 537 break;
513 } 538 }
@@ -524,7 +549,9 @@ out:
524 549
525int perf_event__synthesize_threads(struct perf_tool *tool, 550int perf_event__synthesize_threads(struct perf_tool *tool,
526 perf_event__handler_t process, 551 perf_event__handler_t process,
527 struct machine *machine, bool mmap_data) 552 struct machine *machine,
553 bool mmap_data,
554 unsigned int proc_map_timeout)
528{ 555{
529 DIR *proc; 556 DIR *proc;
530 char proc_path[PATH_MAX]; 557 char proc_path[PATH_MAX];
@@ -564,7 +591,8 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
564 * one thread couldn't be synthesized. 591 * one thread couldn't be synthesized.
565 */ 592 */
566 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid, 593 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
567 1, process, tool, machine, mmap_data); 594 1, process, tool, machine, mmap_data,
595 proc_map_timeout);
568 } 596 }
569 597
570 err = 0; 598 err = 0;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 5dc51ada05df..c53f36384b64 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -265,6 +265,7 @@ struct events_stats {
265 u32 nr_unknown_id; 265 u32 nr_unknown_id;
266 u32 nr_unprocessable_samples; 266 u32 nr_unprocessable_samples;
267 u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; 267 u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX];
268 u32 nr_proc_map_timeout;
268}; 269};
269 270
270struct attr_event { 271struct attr_event {
@@ -383,10 +384,12 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool,
383int perf_event__synthesize_thread_map(struct perf_tool *tool, 384int perf_event__synthesize_thread_map(struct perf_tool *tool,
384 struct thread_map *threads, 385 struct thread_map *threads,
385 perf_event__handler_t process, 386 perf_event__handler_t process,
386 struct machine *machine, bool mmap_data); 387 struct machine *machine, bool mmap_data,
388 unsigned int proc_map_timeout);
387int perf_event__synthesize_threads(struct perf_tool *tool, 389int perf_event__synthesize_threads(struct perf_tool *tool,
388 perf_event__handler_t process, 390 perf_event__handler_t process,
389 struct machine *machine, bool mmap_data); 391 struct machine *machine, bool mmap_data,
392 unsigned int proc_map_timeout);
390int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 393int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
391 perf_event__handler_t process, 394 perf_event__handler_t process,
392 struct machine *machine); 395 struct machine *machine);
@@ -468,7 +471,8 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
468 pid_t pid, pid_t tgid, 471 pid_t pid, pid_t tgid,
469 perf_event__handler_t process, 472 perf_event__handler_t process,
470 struct machine *machine, 473 struct machine *machine,
471 bool mmap_data); 474 bool mmap_data,
475 unsigned int proc_map_timeout);
472 476
473size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); 477size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
474size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 478size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 132e35765101..4744673aff1b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1890,14 +1890,36 @@ int machine__for_each_thread(struct machine *machine,
1890 return rc; 1890 return rc;
1891} 1891}
1892 1892
1893int machines__for_each_thread(struct machines *machines,
1894 int (*fn)(struct thread *thread, void *p),
1895 void *priv)
1896{
1897 struct rb_node *nd;
1898 int rc = 0;
1899
1900 rc = machine__for_each_thread(&machines->host, fn, priv);
1901 if (rc != 0)
1902 return rc;
1903
1904 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
1905 struct machine *machine = rb_entry(nd, struct machine, rb_node);
1906
1907 rc = machine__for_each_thread(machine, fn, priv);
1908 if (rc != 0)
1909 return rc;
1910 }
1911 return rc;
1912}
1913
1893int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1914int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
1894 struct target *target, struct thread_map *threads, 1915 struct target *target, struct thread_map *threads,
1895 perf_event__handler_t process, bool data_mmap) 1916 perf_event__handler_t process, bool data_mmap,
1917 unsigned int proc_map_timeout)
1896{ 1918{
1897 if (target__has_task(target)) 1919 if (target__has_task(target))
1898 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); 1920 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap, proc_map_timeout);
1899 else if (target__has_cpu(target)) 1921 else if (target__has_cpu(target))
1900 return perf_event__synthesize_threads(tool, process, machine, data_mmap); 1922 return perf_event__synthesize_threads(tool, process, machine, data_mmap, proc_map_timeout);
1901 /* command specified */ 1923 /* command specified */
1902 return 0; 1924 return 0;
1903} 1925}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index ca267c41f28d..887798e511e9 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -216,16 +216,22 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
216int machine__for_each_thread(struct machine *machine, 216int machine__for_each_thread(struct machine *machine,
217 int (*fn)(struct thread *thread, void *p), 217 int (*fn)(struct thread *thread, void *p),
218 void *priv); 218 void *priv);
219int machines__for_each_thread(struct machines *machines,
220 int (*fn)(struct thread *thread, void *p),
221 void *priv);
219 222
220int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 223int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
221 struct target *target, struct thread_map *threads, 224 struct target *target, struct thread_map *threads,
222 perf_event__handler_t process, bool data_mmap); 225 perf_event__handler_t process, bool data_mmap,
226 unsigned int proc_map_timeout);
223static inline 227static inline
224int machine__synthesize_threads(struct machine *machine, struct target *target, 228int machine__synthesize_threads(struct machine *machine, struct target *target,
225 struct thread_map *threads, bool data_mmap) 229 struct thread_map *threads, bool data_mmap,
230 unsigned int proc_map_timeout)
226{ 231{
227 return __machine__synthesize_threads(machine, NULL, target, threads, 232 return __machine__synthesize_threads(machine, NULL, target, threads,
228 perf_event__process, data_mmap); 233 perf_event__process, data_mmap,
234 proc_map_timeout);
229} 235}
230 236
231pid_t machine__get_current_tid(struct machine *machine, int cpu); 237pid_t machine__get_current_tid(struct machine *machine, int cpu);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e1cd17c2afab..aa482c10469d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,6 +16,7 @@
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "asm/bug.h" 17#include "asm/bug.h"
18#include "auxtrace.h" 18#include "auxtrace.h"
19#include "thread-stack.h"
19 20
20static int perf_session__deliver_event(struct perf_session *session, 21static int perf_session__deliver_event(struct perf_session *session,
21 union perf_event *event, 22 union perf_event *event,
@@ -1063,6 +1064,8 @@ static int machines__deliver_event(struct machines *machines,
1063 case PERF_RECORD_MMAP: 1064 case PERF_RECORD_MMAP:
1064 return tool->mmap(tool, event, sample, machine); 1065 return tool->mmap(tool, event, sample, machine);
1065 case PERF_RECORD_MMAP2: 1066 case PERF_RECORD_MMAP2:
1067 if (event->header.misc & PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT)
1068 ++evlist->stats.nr_proc_map_timeout;
1066 return tool->mmap2(tool, event, sample, machine); 1069 return tool->mmap2(tool, event, sample, machine);
1067 case PERF_RECORD_COMM: 1070 case PERF_RECORD_COMM:
1068 return tool->comm(tool, event, sample, machine); 1071 return tool->comm(tool, event, sample, machine);
@@ -1359,6 +1362,30 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
1359 ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); 1362 ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events);
1360 1363
1361 events_stats__auxtrace_error_warn(stats); 1364 events_stats__auxtrace_error_warn(stats);
1365
1366 if (stats->nr_proc_map_timeout != 0) {
1367 ui__warning("%d map information files for pre-existing threads were\n"
1368 "not processed, if there are samples for addresses they\n"
1369 "will not be resolved, you may find out which are these\n"
1370 "threads by running with -v and redirecting the output\n"
1371 "to a file.\n"
1372 "The time limit to process proc map is too short?\n"
1373 "Increase it by --proc-map-timeout\n",
1374 stats->nr_proc_map_timeout);
1375 }
1376}
1377
1378static int perf_session__flush_thread_stack(struct thread *thread,
1379 void *p __maybe_unused)
1380{
1381 return thread_stack__flush(thread);
1382}
1383
1384static int perf_session__flush_thread_stacks(struct perf_session *session)
1385{
1386 return machines__for_each_thread(&session->machines,
1387 perf_session__flush_thread_stack,
1388 NULL);
1362} 1389}
1363 1390
1364volatile int session_done; 1391volatile int session_done;
@@ -1450,6 +1477,9 @@ done:
1450 if (err) 1477 if (err)
1451 goto out_err; 1478 goto out_err;
1452 err = auxtrace__flush_events(session, tool); 1479 err = auxtrace__flush_events(session, tool);
1480 if (err)
1481 goto out_err;
1482 err = perf_session__flush_thread_stacks(session);
1453out_err: 1483out_err:
1454 free(buf); 1484 free(buf);
1455 perf_session__warn_about_errors(session); 1485 perf_session__warn_about_errors(session);
@@ -1600,6 +1630,9 @@ out:
1600 if (err) 1630 if (err)
1601 goto out_err; 1631 goto out_err;
1602 err = auxtrace__flush_events(session, tool); 1632 err = auxtrace__flush_events(session, tool);
1633 if (err)
1634 goto out_err;
1635 err = perf_session__flush_thread_stacks(session);
1603out_err: 1636out_err:
1604 ui_progress__finish(); 1637 ui_progress__finish();
1605 perf_session__warn_about_errors(session); 1638 perf_session__warn_about_errors(session);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 09d4696fd9a1..4c65a143a34c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -182,18 +182,16 @@ static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
182 182
183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
184{ 184{
185 u64 ip_l, ip_r;
186
187 if (!sym_l || !sym_r) 185 if (!sym_l || !sym_r)
188 return cmp_null(sym_l, sym_r); 186 return cmp_null(sym_l, sym_r);
189 187
190 if (sym_l == sym_r) 188 if (sym_l == sym_r)
191 return 0; 189 return 0;
192 190
193 ip_l = sym_l->start; 191 if (sym_l->start != sym_r->start)
194 ip_r = sym_r->start; 192 return (int64_t)(sym_r->start - sym_l->start);
195 193
196 return (int64_t)(ip_r - ip_l); 194 return (int64_t)(sym_r->end - sym_l->end);
197} 195}
198 196
199static int64_t 197static int64_t
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 9ed59a452d1f..679688e70ae7 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -219,7 +219,7 @@ static int thread_stack__call_return(struct thread *thread,
219 return crp->process(&cr, crp->data); 219 return crp->process(&cr, crp->data);
220} 220}
221 221
222static int thread_stack__flush(struct thread *thread, struct thread_stack *ts) 222static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
223{ 223{
224 struct call_return_processor *crp = ts->crp; 224 struct call_return_processor *crp = ts->crp;
225 int err; 225 int err;
@@ -242,6 +242,14 @@ static int thread_stack__flush(struct thread *thread, struct thread_stack *ts)
242 return 0; 242 return 0;
243} 243}
244 244
245int thread_stack__flush(struct thread *thread)
246{
247 if (thread->ts)
248 return __thread_stack__flush(thread, thread->ts);
249
250 return 0;
251}
252
245int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, 253int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
246 u64 to_ip, u16 insn_len, u64 trace_nr) 254 u64 to_ip, u16 insn_len, u64 trace_nr)
247{ 255{
@@ -264,7 +272,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
264 */ 272 */
265 if (trace_nr != thread->ts->trace_nr) { 273 if (trace_nr != thread->ts->trace_nr) {
266 if (thread->ts->trace_nr) 274 if (thread->ts->trace_nr)
267 thread_stack__flush(thread, thread->ts); 275 __thread_stack__flush(thread, thread->ts);
268 thread->ts->trace_nr = trace_nr; 276 thread->ts->trace_nr = trace_nr;
269 } 277 }
270 278
@@ -297,7 +305,7 @@ void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
297 305
298 if (trace_nr != thread->ts->trace_nr) { 306 if (trace_nr != thread->ts->trace_nr) {
299 if (thread->ts->trace_nr) 307 if (thread->ts->trace_nr)
300 thread_stack__flush(thread, thread->ts); 308 __thread_stack__flush(thread, thread->ts);
301 thread->ts->trace_nr = trace_nr; 309 thread->ts->trace_nr = trace_nr;
302 } 310 }
303} 311}
@@ -305,7 +313,7 @@ void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
305void thread_stack__free(struct thread *thread) 313void thread_stack__free(struct thread *thread)
306{ 314{
307 if (thread->ts) { 315 if (thread->ts) {
308 thread_stack__flush(thread, thread->ts); 316 __thread_stack__flush(thread, thread->ts);
309 zfree(&thread->ts->stack); 317 zfree(&thread->ts->stack);
310 zfree(&thread->ts); 318 zfree(&thread->ts);
311 } 319 }
@@ -689,7 +697,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
689 697
690 /* Flush stack on exec */ 698 /* Flush stack on exec */
691 if (ts->comm != comm && thread->pid_ == thread->tid) { 699 if (ts->comm != comm && thread->pid_ == thread->tid) {
692 err = thread_stack__flush(thread, ts); 700 err = __thread_stack__flush(thread, ts);
693 if (err) 701 if (err)
694 return err; 702 return err;
695 ts->comm = comm; 703 ts->comm = comm;
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
index b843bbef8ba2..e1528f1374c3 100644
--- a/tools/perf/util/thread-stack.h
+++ b/tools/perf/util/thread-stack.h
@@ -96,6 +96,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
96void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); 96void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
97void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 97void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
98 size_t sz, u64 ip); 98 size_t sz, u64 ip);
99int thread_stack__flush(struct thread *thread);
99void thread_stack__free(struct thread *thread); 100void thread_stack__free(struct thread *thread);
100 101
101struct call_return_processor * 102struct call_return_processor *