diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 118 |
1 files changed, 66 insertions, 52 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7e2e72e6d9d1..94af190f6843 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -34,7 +34,7 @@ #include "util/top.h" #include "util/util.h" #include <linux/rbtree.h> -#include "util/parse-options.h" +#include <subcmd/parse-options.h> #include "util/parse-events.h" #include "util/cpumap.h" #include "util/xyarray.h" @@ -175,42 +175,40 @@ static void perf_top__record_precise_ip(struct perf_top *top, int counter, u64 ip) { struct annotation *notes; - struct symbol *sym; + struct symbol *sym = he->ms.sym; int err = 0; - if (he == NULL || he->ms.sym == NULL || - ((top->sym_filter_entry == NULL || - top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) + if (sym == NULL || (use_browser == 0 && + (top->sym_filter_entry == NULL || + top->sym_filter_entry->ms.sym != sym))) return; - sym = he->ms.sym; notes = symbol__annotation(sym); if (pthread_mutex_trylock(¬es->lock)) return; - ip = he->ms.map->map_ip(he->ms.map, ip); - - if (ui__has_annotation()) - err = hist_entry__inc_addr_samples(he, counter, ip); + err = hist_entry__inc_addr_samples(he, counter, ip); pthread_mutex_unlock(¬es->lock); - /* - * This function is now called with he->hists->lock held. - * Release it before going to sleep. - */ - pthread_mutex_unlock(&he->hists->lock); + if (unlikely(err)) { + /* + * This function is now called with he->hists->lock held. + * Release it before going to sleep. + */ + pthread_mutex_unlock(&he->hists->lock); + + if (err == -ERANGE && !he->ms.map->erange_warned) + ui__warn_map_erange(he->ms.map, sym, ip); + else if (err == -ENOMEM) { + pr_err("Not enough memory for annotating '%s' symbol!\n", + sym->name); + sleep(1); + } - if (err == -ERANGE && !he->ms.map->erange_warned) - ui__warn_map_erange(he->ms.map, sym, ip); - else if (err == -ENOMEM) { - pr_err("Not enough memory for annotating '%s' symbol!\n", - sym->name); - sleep(1); + pthread_mutex_lock(&he->hists->lock); } - - pthread_mutex_lock(&he->hists->lock); } static void perf_top__show_details(struct perf_top *top) @@ -254,7 +252,8 @@ static void perf_top__print_sym_table(struct perf_top *top) char bf[160]; int printed = 0; const int win_width = top->winsize.ws_col - 1; - struct hists *hists = evsel__hists(top->sym_evsel); + struct perf_evsel *evsel = top->sym_evsel; + struct hists *hists = evsel__hists(evsel); puts(CONSOLE_CLEAR); @@ -290,7 +289,7 @@ static void perf_top__print_sym_table(struct perf_top *top) } hists__collapse_resort(hists, NULL); - hists__output_resort(hists, NULL); + perf_evsel__output_resort(evsel, NULL); hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); @@ -542,6 +541,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) static void perf_top__sort_new_samples(void *arg) { struct perf_top *t = arg; + struct perf_evsel *evsel = t->sym_evsel; struct hists *hists; perf_top__reset_sample_counters(t); @@ -549,7 +549,7 @@ static void perf_top__sort_new_samples(void *arg) if (t->evlist->selected != NULL) t->sym_evsel = t->evlist->selected; - hists = evsel__hists(t->sym_evsel); + hists = evsel__hists(evsel); if (t->evlist->enabled) { if (t->zero) { @@ -561,7 +561,7 @@ static void perf_top__sort_new_samples(void *arg) } hists__collapse_resort(hists, NULL); - hists__output_resort(hists, NULL); + perf_evsel__output_resort(evsel, NULL); } static void *display_thread_tui(void *arg) @@ -687,14 +687,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, struct hist_entry *he = iter->he; struct perf_evsel *evsel = iter->evsel; - if (sort__has_sym && single) { - u64 ip = al->addr; - - if (al->map) - ip = al->map->unmap_ip(al->map, ip); - - perf_top__record_precise_ip(top, he, evsel->idx, ip); - } + if (sort__has_sym && single) + perf_top__record_precise_ip(top, he, evsel->idx, al->addr); hist__account_cycles(iter->sample->branch_stack, al, iter->sample, !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); @@ -964,7 +958,7 @@ static int __cmd_top(struct perf_top *top) if (ret) goto out_delete; - if (perf_session__register_idle_thread(top->session) == NULL) + if (perf_session__register_idle_thread(top->session) < 0) goto out_delete; machine__synthesize_threads(&top->session->machines.host, &opts->target, @@ -1071,7 +1065,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) return parse_callchain_top_opt(arg); } -static int perf_top_config(const char *var, const char *value, void *cb) +static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused) { if (!strcmp(var, "top.call-graph")) var = "call-graph.record-mode"; /* fall-through */ @@ -1080,7 +1074,7 @@ static int perf_top_config(const char *var, const char *value, void *cb) return 0; } - return perf_default_config(var, value, cb); + return 0; } static int @@ -1218,6 +1212,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) OPT_CALLBACK('j', "branch-filter", &opts->branch_stack, "branch filter mask", "branch stack filter modes", parse_branch_stack), + OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, + "Show raw trace event output (do not use print fmt or plugins)"), + OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, + "Show entries in a hierarchy"), OPT_END() }; const char * const top_usage[] = { @@ -1239,11 +1237,37 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(top_usage, options); + if (!top.evlist->nr_entries && + perf_evlist__add_default(top.evlist) < 0) { + pr_err("Not enough memory for event selector list\n"); + goto out_delete_evlist; + } + + if (symbol_conf.report_hierarchy) { + /* disable incompatible options */ + symbol_conf.event_group = false; + symbol_conf.cumulate_callchain = false; + + if (field_order) { + pr_err("Error: --hierarchy and --fields options cannot be used together\n"); + parse_options_usage(top_usage, options, "fields", 0); + parse_options_usage(NULL, options, "hierarchy", 0); + goto out_delete_evlist; + } + } + sort__mode = SORT_MODE__TOP; /* display thread wants entries to be collapsed in a different tree */ sort__need_collapse = 1; - if (setup_sorting() < 0) { + if (top.use_stdio) + use_browser = 0; + else if (top.use_tui) + use_browser = 1; + + setup_browser(false); + + if (setup_sorting(top.evlist) < 0) { if (sort_order) parse_options_usage(top_usage, options, "s", 1); if (field_order) @@ -1252,13 +1276,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) goto out_delete_evlist; } - if (top.use_stdio) - use_browser = 0; - else if (top.use_tui) - use_browser = 1; - - setup_browser(false); - status = target__validate(target); if (status) { target__strerror(target, status, errbuf, BUFSIZ); @@ -1279,12 +1296,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (target__none(target)) target->system_wide = true; - if (perf_evlist__create_maps(top.evlist, target) < 0) - usage_with_options(top_usage, options); - - if (!top.evlist->nr_entries && - perf_evlist__add_default(top.evlist) < 0) { - ui__error("Not enough memory for event selector list\n"); + if (perf_evlist__create_maps(top.evlist, target) < 0) { + ui__error("Couldn't create thread/CPU maps: %s\n", + errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf))); goto out_delete_evlist; } |