diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 90 |
1 files changed, 52 insertions, 38 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5b389ce4cd15..377971dc89a3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
196 | 196 | ||
197 | pthread_mutex_unlock(¬es->lock); | 197 | pthread_mutex_unlock(¬es->lock); |
198 | 198 | ||
199 | /* | ||
200 | * This function is now called with he->hists->lock held. | ||
201 | * Release it before going to sleep. | ||
202 | */ | ||
203 | pthread_mutex_unlock(&he->hists->lock); | ||
204 | |||
199 | if (err == -ERANGE && !he->ms.map->erange_warned) | 205 | if (err == -ERANGE && !he->ms.map->erange_warned) |
200 | ui__warn_map_erange(he->ms.map, sym, ip); | 206 | ui__warn_map_erange(he->ms.map, sym, ip); |
201 | else if (err == -ENOMEM) { | 207 | else if (err == -ENOMEM) { |
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
203 | sym->name); | 209 | sym->name); |
204 | sleep(1); | 210 | sleep(1); |
205 | } | 211 | } |
212 | |||
213 | pthread_mutex_lock(&he->hists->lock); | ||
206 | } | 214 | } |
207 | 215 | ||
208 | static void perf_top__show_details(struct perf_top *top) | 216 | static void perf_top__show_details(struct perf_top *top) |
@@ -238,27 +246,6 @@ out_unlock: | |||
238 | pthread_mutex_unlock(¬es->lock); | 246 | pthread_mutex_unlock(¬es->lock); |
239 | } | 247 | } |
240 | 248 | ||
241 | static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, | ||
242 | struct addr_location *al, | ||
243 | struct perf_sample *sample) | ||
244 | { | ||
245 | struct hist_entry *he; | ||
246 | |||
247 | pthread_mutex_lock(&evsel->hists.lock); | ||
248 | he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, | ||
249 | sample->period, sample->weight, | ||
250 | sample->transaction); | ||
251 | pthread_mutex_unlock(&evsel->hists.lock); | ||
252 | if (he == NULL) | ||
253 | return NULL; | ||
254 | |||
255 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | ||
256 | if (!he->filtered) | ||
257 | evsel->hists.stats.nr_non_filtered_samples++; | ||
258 | |||
259 | return he; | ||
260 | } | ||
261 | |||
262 | static void perf_top__print_sym_table(struct perf_top *top) | 249 | static void perf_top__print_sym_table(struct perf_top *top) |
263 | { | 250 | { |
264 | char bf[160]; | 251 | char bf[160]; |
@@ -662,6 +649,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | |||
662 | return 0; | 649 | return 0; |
663 | } | 650 | } |
664 | 651 | ||
652 | static int hist_iter__top_callback(struct hist_entry_iter *iter, | ||
653 | struct addr_location *al, bool single, | ||
654 | void *arg) | ||
655 | { | ||
656 | struct perf_top *top = arg; | ||
657 | struct hist_entry *he = iter->he; | ||
658 | struct perf_evsel *evsel = iter->evsel; | ||
659 | |||
660 | if (sort__has_sym && single) { | ||
661 | u64 ip = al->addr; | ||
662 | |||
663 | if (al->map) | ||
664 | ip = al->map->unmap_ip(al->map, ip); | ||
665 | |||
666 | perf_top__record_precise_ip(top, he, evsel->idx, ip); | ||
667 | } | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
665 | static void perf_event__process_sample(struct perf_tool *tool, | 672 | static void perf_event__process_sample(struct perf_tool *tool, |
666 | const union perf_event *event, | 673 | const union perf_event *event, |
667 | struct perf_evsel *evsel, | 674 | struct perf_evsel *evsel, |
@@ -669,8 +676,6 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
669 | struct machine *machine) | 676 | struct machine *machine) |
670 | { | 677 | { |
671 | struct perf_top *top = container_of(tool, struct perf_top, tool); | 678 | struct perf_top *top = container_of(tool, struct perf_top, tool); |
672 | struct symbol *parent = NULL; | ||
673 | u64 ip = sample->ip; | ||
674 | struct addr_location al; | 679 | struct addr_location al; |
675 | int err; | 680 | int err; |
676 | 681 | ||
@@ -745,25 +750,23 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
745 | } | 750 | } |
746 | 751 | ||
747 | if (al.sym == NULL || !al.sym->ignore) { | 752 | if (al.sym == NULL || !al.sym->ignore) { |
748 | struct hist_entry *he; | 753 | struct hist_entry_iter iter = { |
754 | .add_entry_cb = hist_iter__top_callback, | ||
755 | }; | ||
749 | 756 | ||
750 | err = sample__resolve_callchain(sample, &parent, evsel, &al, | 757 | if (symbol_conf.cumulate_callchain) |
751 | top->max_stack); | 758 | iter.ops = &hist_iter_cumulative; |
752 | if (err) | 759 | else |
753 | return; | 760 | iter.ops = &hist_iter_normal; |
754 | 761 | ||
755 | he = perf_evsel__add_hist_entry(evsel, &al, sample); | 762 | pthread_mutex_lock(&evsel->hists.lock); |
756 | if (he == NULL) { | ||
757 | pr_err("Problem incrementing symbol period, skipping event\n"); | ||
758 | return; | ||
759 | } | ||
760 | 763 | ||
761 | err = hist_entry__append_callchain(he, sample); | 764 | err = hist_entry_iter__add(&iter, &al, evsel, sample, |
762 | if (err) | 765 | top->max_stack, top); |
763 | return; | 766 | if (err < 0) |
767 | pr_err("Problem incrementing symbol period, skipping event\n"); | ||
764 | 768 | ||
765 | if (sort__has_sym) | 769 | pthread_mutex_unlock(&evsel->hists.lock); |
766 | perf_top__record_precise_ip(top, he, evsel->idx, ip); | ||
767 | } | 770 | } |
768 | 771 | ||
769 | return; | 772 | return; |
@@ -1001,6 +1004,10 @@ static int perf_top_config(const char *var, const char *value, void *cb) | |||
1001 | 1004 | ||
1002 | if (!strcmp(var, "top.call-graph")) | 1005 | if (!strcmp(var, "top.call-graph")) |
1003 | return record_parse_callchain(value, &top->record_opts); | 1006 | return record_parse_callchain(value, &top->record_opts); |
1007 | if (!strcmp(var, "top.children")) { | ||
1008 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | ||
1009 | return 0; | ||
1010 | } | ||
1004 | 1011 | ||
1005 | return perf_default_config(var, value, cb); | 1012 | return perf_default_config(var, value, cb); |
1006 | } | 1013 | } |
@@ -1095,6 +1102,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1095 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1102 | OPT_CALLBACK(0, "call-graph", &top.record_opts, |
1096 | "mode[,dump_size]", record_callchain_help, | 1103 | "mode[,dump_size]", record_callchain_help, |
1097 | &parse_callchain_opt), | 1104 | &parse_callchain_opt), |
1105 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, | ||
1106 | "Accumulate callchains of children and show total overhead as well"), | ||
1098 | OPT_INTEGER(0, "max-stack", &top.max_stack, | 1107 | OPT_INTEGER(0, "max-stack", &top.max_stack, |
1099 | "Set the maximum stack depth when parsing the callchain. " | 1108 | "Set the maximum stack depth when parsing the callchain. " |
1100 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 1109 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), |
@@ -1200,6 +1209,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1200 | 1209 | ||
1201 | top.sym_evsel = perf_evlist__first(top.evlist); | 1210 | top.sym_evsel = perf_evlist__first(top.evlist); |
1202 | 1211 | ||
1212 | if (!symbol_conf.use_callchain) { | ||
1213 | symbol_conf.cumulate_callchain = false; | ||
1214 | perf_hpp__cancel_cumulate(); | ||
1215 | } | ||
1216 | |||
1203 | symbol_conf.priv_size = sizeof(struct annotation); | 1217 | symbol_conf.priv_size = sizeof(struct annotation); |
1204 | 1218 | ||
1205 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1219 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |