diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-06-19 19:11:11 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-06-19 19:11:11 -0400 |
commit | a9a3cd900fbbcbf837d65653105e7bfc583ced09 (patch) | |
tree | f59dd3c9d866c2fa8aa85b90c1eac83bf4f515a9 /tools | |
parent | 79928928c5a27d58ae48285d2a3f7aa835db7547 (diff) | |
parent | 9d9cad763ca79dd3697e9f2d1df648e37496582b (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')
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 | |||
154 | SEE ALSO | 160 | SEE ALSO |
155 | -------- | 161 | -------- |
156 | linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], | 162 | linkperf: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 | |||
271 | snapshot can be specified. In Snapshot Mode, trace data is captured only when | 271 | snapshot can be specified. In Snapshot Mode, trace data is captured only when |
272 | signal SIGUSR2 is received. | 272 | signal SIGUSR2 is received. |
273 | 273 | ||
274 | --proc-map-timeout:: | ||
275 | When processing pre-existing threads /proc/XXX/mmap, it may take a long time, | ||
276 | because the file may be huge. A time out is needed in such cases. | ||
277 | This option sets the time out limit. The default value is 500 ms. | ||
278 | |||
274 | SEE ALSO | 279 | SEE ALSO |
275 | -------- | 280 | -------- |
276 | linkperf:perf-stat[1], linkperf:perf-list[1] | 281 | linkperf: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 | ||
205 | INTERACTIVE PROMPTING KEYS | 211 | INTERACTIVE 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 | |||
124 | PAGEFAULTS | 129 | PAGEFAULTS |
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 | ||
74 | struct option; | 75 | struct 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 | ||
135 | static int synth_process(struct machine *machine) | 135 | static 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 | ||
14 | struct disasm_line_samples { | ||
15 | double percent; | ||
16 | u64 nr; | ||
17 | }; | ||
18 | |||
14 | struct browser_disasm_line { | 19 | struct 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 | ||
26 | static struct annotate_browser_opt { | 31 | static 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(¬es->src->source, pos); | 377 | next = disasm__get_next_ip_line(¬es->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: | |||
832 | int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, | 852 | int 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 | ||
427 | static int hist_browser__run(struct hist_browser *browser) | 427 | static 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 | ||
656 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | 656 | double 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 | |||
72 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 72 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
73 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 73 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
74 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | 74 | double 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 | ||
77 | struct sym_hist { | 77 | struct sym_hist { |
78 | u64 sum; | 78 | u64 sum; |
79 | u64 addr[0]; | 79 | u64 addr[0]; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | struct source_line_percent { | 82 | struct source_line_samples { |
83 | double percent; | 83 | double percent; |
84 | double percent_sum; | 84 | double percent_sum; |
85 | double nr; | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | struct source_line { | 88 | struct 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 | ||
318 | out: | ||
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 | ||
525 | int perf_event__synthesize_threads(struct perf_tool *tool, | 550 | int 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 | ||
270 | struct attr_event { | 271 | struct attr_event { |
@@ -383,10 +384,12 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool, | |||
383 | int perf_event__synthesize_thread_map(struct perf_tool *tool, | 384 | int 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); | ||
387 | int perf_event__synthesize_threads(struct perf_tool *tool, | 389 | int 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); | ||
390 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 393 | int 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 | ||
473 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 477 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); |
474 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); | 478 | size_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 | ||
1893 | int 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 | |||
1893 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | 1914 | int __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); | |||
216 | int machine__for_each_thread(struct machine *machine, | 216 | int 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); |
219 | int machines__for_each_thread(struct machines *machines, | ||
220 | int (*fn)(struct thread *thread, void *p), | ||
221 | void *priv); | ||
219 | 222 | ||
220 | int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, | 223 | int __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); | ||
223 | static inline | 227 | static inline |
224 | int machine__synthesize_threads(struct machine *machine, struct target *target, | 228 | int 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 | ||
231 | pid_t machine__get_current_tid(struct machine *machine, int cpu); | 237 | pid_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 | ||
20 | static int perf_session__deliver_event(struct perf_session *session, | 21 | static 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 | |||
1378 | static int perf_session__flush_thread_stack(struct thread *thread, | ||
1379 | void *p __maybe_unused) | ||
1380 | { | ||
1381 | return thread_stack__flush(thread); | ||
1382 | } | ||
1383 | |||
1384 | static 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 | ||
1364 | volatile int session_done; | 1391 | volatile 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); | ||
1453 | out_err: | 1483 | out_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); | ||
1603 | out_err: | 1636 | out_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 | ||
183 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) | 183 | static 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 | ||
199 | static int64_t | 197 | static 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 | ||
222 | static int thread_stack__flush(struct thread *thread, struct thread_stack *ts) | 222 | static 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 | ||
245 | int 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 | |||
245 | int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | 253 | int 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) | |||
305 | void thread_stack__free(struct thread *thread) | 313 | void 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, | |||
96 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); | 96 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); |
97 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | 97 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, |
98 | size_t sz, u64 ip); | 98 | size_t sz, u64 ip); |
99 | int thread_stack__flush(struct thread *thread); | ||
99 | void thread_stack__free(struct thread *thread); | 100 | void thread_stack__free(struct thread *thread); |
100 | 101 | ||
101 | struct call_return_processor * | 102 | struct call_return_processor * |