diff options
Diffstat (limited to 'tools/perf/ui/browsers/hists.c')
| -rw-r--r-- | tools/perf/ui/browsers/hists.c | 503 |
1 files changed, 302 insertions, 201 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index aa22704047d..04a229aa5c0 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2,7 +2,6 @@ #include "../libslang.h" #include <stdlib.h> #include <string.h> -#include <newt.h> #include <linux/rbtree.h> #include "../../util/evsel.h" @@ -18,6 +17,7 @@ #include "../util.h" #include "../ui.h" #include "map.h" +#include "annotate.h" struct hist_browser { struct ui_browser b; @@ -26,13 +26,36 @@ struct hist_browser { struct map_symbol *selection; int print_seq; bool show_dso; - bool has_symbols; + float min_pcnt; + u64 nr_non_filtered_entries; + u64 nr_callchain_rows; }; extern void hist_browser__init_hpp(void); static int hists__browser_title(struct hists *hists, char *bf, size_t size, const char *ev_name); +static void hist_browser__update_nr_entries(struct hist_browser *hb); + +static struct rb_node *hists__filter_entries(struct rb_node *nd, + float min_pcnt); + +static bool hist_browser__has_filter(struct hist_browser *hb) +{ + return hists__has_filter(hb->hists) || hb->min_pcnt; +} + +static u32 hist_browser__nr_entries(struct hist_browser *hb) +{ + u32 nr_entries; + + if (hist_browser__has_filter(hb)) + nr_entries = hb->nr_non_filtered_entries; + else + nr_entries = hb->hists->nr_entries; + + return nr_entries + hb->nr_callchain_rows; +} static void hist_browser__refresh_dimensions(struct hist_browser *browser) { @@ -43,7 +66,14 @@ static void hist_browser__refresh_dimensions(struct hist_browser *browser) static void hist_browser__reset(struct hist_browser *browser) { - browser->b.nr_entries = browser->hists->nr_entries; + /* + * The hists__remove_entry_filter() already folds non-filtered + * entries so we can assume it has 0 callchain rows. + */ + browser->nr_callchain_rows = 0; + + hist_browser__update_nr_entries(browser); + browser->b.nr_entries = hist_browser__nr_entries(browser); hist_browser__refresh_dimensions(browser); ui_browser__reset_index(&browser->b); } @@ -198,14 +228,16 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser) struct hist_entry *he = browser->he_selection; hist_entry__init_have_children(he); - browser->hists->nr_entries -= he->nr_rows; + browser->b.nr_entries -= he->nr_rows; + browser->nr_callchain_rows -= he->nr_rows; if (he->ms.unfolded) he->nr_rows = callchain__count_rows(&he->sorted_chain); else he->nr_rows = 0; - browser->hists->nr_entries += he->nr_rows; - browser->b.nr_entries = browser->hists->nr_entries; + + browser->b.nr_entries += he->nr_rows; + browser->nr_callchain_rows += he->nr_rows; return true; } @@ -280,23 +312,27 @@ static void hist_entry__set_folding(struct hist_entry *he, bool unfold) he->nr_rows = 0; } -static void hists__set_folding(struct hists *hists, bool unfold) +static void +__hist_browser__set_folding(struct hist_browser *browser, bool unfold) { struct rb_node *nd; + struct hists *hists = browser->hists; - hists->nr_entries = 0; - - for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { + for (nd = rb_first(&hists->entries); + (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; + nd = rb_next(nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); hist_entry__set_folding(he, unfold); - hists->nr_entries += 1 + he->nr_rows; + browser->nr_callchain_rows += he->nr_rows; } } static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) { - hists__set_folding(browser->hists, unfold); - browser->b.nr_entries = browser->hists->nr_entries; + browser->nr_callchain_rows = 0; + __hist_browser__set_folding(browser, unfold); + + browser->b.nr_entries = hist_browser__nr_entries(browser); /* Go to the start, we may be way after valid entries after a collapse */ ui_browser__reset_index(&browser->b); } @@ -318,7 +354,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, int delay_secs = hbt ? hbt->refresh : 0; browser->b.entries = &browser->hists->entries; - browser->b.nr_entries = browser->hists->nr_entries; + browser->b.nr_entries = hist_browser__nr_entries(browser); hist_browser__refresh_dimensions(browser); hists__browser_title(browser->hists, title, sizeof(title), ev_name); @@ -331,9 +367,15 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, key = ui_browser__run(&browser->b, delay_secs); switch (key) { - case K_TIMER: + case K_TIMER: { + u64 nr_entries; hbt->timer(hbt->arg); - ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); + + if (hist_browser__has_filter(browser)) + hist_browser__update_nr_entries(browser); + + nr_entries = hist_browser__nr_entries(browser); + ui_browser__update_nr_entries(&browser->b, nr_entries); if (browser->hists->stats.nr_lost_warned != browser->hists->stats.nr_events[PERF_RECORD_LOST]) { @@ -345,6 +387,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, hists__browser_title(browser->hists, title, sizeof(title), ev_name); ui_browser__show_title(&browser->b, title); continue; + } case 'D': { /* Debug */ static int seq; struct hist_entry *h = rb_entry(browser->b.top, @@ -573,124 +616,74 @@ struct hpp_arg { bool current_entry; }; -static int __hpp__color_callchain(struct hpp_arg *arg) +static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) { - if (!symbol_conf.use_callchain) - return 0; - - slsmg_printf("%c ", arg->folded_sign); - return 2; -} - -static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, - u64 (*get_field)(struct hist_entry *), - int (*callchain_cb)(struct hpp_arg *)) -{ - int ret = 0; - double percent = 0.0; - struct hists *hists = he->hists; struct hpp_arg *arg = hpp->ptr; + int ret; + va_list args; + double percent; - if (hists->stats.total_period) - percent = 100.0 * get_field(he) / hists->stats.total_period; + va_start(args, fmt); + percent = va_arg(args, double); + va_end(args); ui_browser__set_percent_color(arg->b, percent, arg->current_entry); - if (callchain_cb) - ret += callchain_cb(arg); - - ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); + ret = scnprintf(hpp->buf, hpp->size, fmt, percent); slsmg_printf("%s", hpp->buf); - if (symbol_conf.event_group) { - int prev_idx, idx_delta; - struct perf_evsel *evsel = hists_to_evsel(hists); - struct hist_entry *pair; - int nr_members = evsel->nr_members; - - if (nr_members <= 1) - goto out; - - prev_idx = perf_evsel__group_idx(evsel); - - list_for_each_entry(pair, &he->pairs.head, pairs.node) { - u64 period = get_field(pair); - u64 total = pair->hists->stats.total_period; - - if (!total) - continue; - - evsel = hists_to_evsel(pair->hists); - idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; - - while (idx_delta--) { - /* - * zero-fill group members in the middle which - * have no sample - */ - ui_browser__set_percent_color(arg->b, 0.0, - arg->current_entry); - ret += scnprintf(hpp->buf, hpp->size, - " %6.2f%%", 0.0); - slsmg_printf("%s", hpp->buf); - } - - percent = 100.0 * period / total; - ui_browser__set_percent_color(arg->b, percent, - arg->current_entry); - ret += scnprintf(hpp->buf, hpp->size, - " %6.2f%%", percent); - slsmg_printf("%s", hpp->buf); - - prev_idx = perf_evsel__group_idx(evsel); - } - - idx_delta = nr_members - prev_idx - 1; - - while (idx_delta--) { - /* - * zero-fill group members at last which have no sample - */ - ui_browser__set_percent_color(arg->b, 0.0, - arg->current_entry); - ret += scnprintf(hpp->buf, hpp->size, - " %6.2f%%", 0.0); - slsmg_printf("%s", hpp->buf); - } - } -out: - if (!arg->current_entry || !arg->b->navkeypressed) - ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); - + advance_hpp(hpp, ret); return ret; } -#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ +#define __HPP_COLOR_PERCENT_FN(_type, _field) \ static u64 __hpp_get_##_field(struct hist_entry *he) \ { \ return he->stat._field; \ } \ \ -static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ - struct hist_entry *he) \ +static int \ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \ + __hpp__slsmg_color_printf, true); \ +} + +#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ +static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int \ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ { \ - return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ + if (!symbol_conf.cumulate_callchain) { \ + int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ + slsmg_printf("%s", hpp->buf); \ + \ + return ret; \ + } \ + return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ + __hpp__slsmg_color_printf, true); \ } -__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain) -__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL) -__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL) -__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL) -__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) +__HPP_COLOR_PERCENT_FN(overhead, period) +__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) +__HPP_COLOR_PERCENT_FN(overhead_us, period_us) +__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) +__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) #undef __HPP_COLOR_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FN void hist_browser__init_hpp(void) { - perf_hpp__column_enable(PERF_HPP__OVERHEAD); - - perf_hpp__init(); - perf_hpp__format[PERF_HPP__OVERHEAD].color = hist_browser__hpp_color_overhead; perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = @@ -701,6 +694,8 @@ void hist_browser__init_hpp(void) hist_browser__hpp_color_overhead_guest_sys; perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = hist_browser__hpp_color_overhead_guest_us; + perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = + hist_browser__hpp_color_overhead_acc; } static int hist_browser__show_entry(struct hist_browser *browser, @@ -728,7 +723,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, if (row_offset == 0) { struct hpp_arg arg = { - .b = &browser->b, + .b = &browser->b, .folded_sign = folded_sign, .current_entry = current_entry, }; @@ -741,16 +736,32 @@ static int hist_browser__show_entry(struct hist_browser *browser, ui_browser__gotorc(&browser->b, row, 0); perf_hpp__for_each_format(fmt) { - if (!first) { + if (perf_hpp__should_skip(fmt)) + continue; + + if (current_entry && browser->b.navkeypressed) { + ui_browser__set_color(&browser->b, + HE_COLORSET_SELECTED); + } else { + ui_browser__set_color(&browser->b, + HE_COLORSET_NORMAL); + } + + if (first) { + if (symbol_conf.use_callchain) { + slsmg_printf("%c ", folded_sign); + width -= 2; + } + first = false; + } else { slsmg_printf(" "); width -= 2; } - first = false; if (fmt->color) { - width -= fmt->color(&hpp, entry); + width -= fmt->color(fmt, &hpp, entry); } else { - width -= fmt->entry(&hpp, entry); + width -= fmt->entry(fmt, &hpp, entry); slsmg_printf("%s", s); } } @@ -759,8 +770,8 @@ static int hist_browser__show_entry(struct hist_browser *browser, if (!browser->b.navkeypressed) width += 1; - hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); - slsmg_write_nstring(s, width); + slsmg_write_nstring("", width); + ++row; ++printed; } else @@ -797,10 +808,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) for (nd = browser->top; nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); + float percent; if (h->filtered) continue; + percent = hist_entry__get_percent_limit(h); + if (percent < hb->min_pcnt) + continue; + row += hist_browser__show_entry(hb, h, row); if (row == browser->height) break; @@ -809,11 +825,14 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) return row; } -static struct rb_node *hists__filter_entries(struct rb_node *nd) +static struct rb_node *hists__filter_entries(struct rb_node *nd, + float min_pcnt) { while (nd != NULL) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - if (!h->filtered) + float percent = hist_entry__get_percent_limit(h); + + if (!h->filtered && percent >= min_pcnt) return nd; nd = rb_next(nd); @@ -822,11 +841,14 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd) return NULL; } -static struct rb_node *hists__filter_prev_entries(struct rb_node *nd) +static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, + float min_pcnt) { while (nd != NULL) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - if (!h->filtered) + float percent = hist_entry__get_percent_limit(h); + + if (!h->filtered && percent >= min_pcnt) return nd; nd = rb_prev(nd); @@ -841,6 +863,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser, struct hist_entry *h; struct rb_node *nd; bool first = true; + struct hist_browser *hb; + + hb = container_of(browser, struct hist_browser, b); if (browser->nr_entries == 0) return; @@ -849,13 +874,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser, switch (whence) { case SEEK_SET: - nd = hists__filter_entries(rb_first(browser->entries)); + nd = hists__filter_entries(rb_first(browser->entries), + hb->min_pcnt); break; case SEEK_CUR: nd = browser->top; goto do_offset; case SEEK_END: - nd = hists__filter_prev_entries(rb_last(browser->entries)); + nd = hists__filter_prev_entries(rb_last(browser->entries), + hb->min_pcnt); first = false; break; default: @@ -898,7 +925,7 @@ do_offset: break; } } - nd = hists__filter_entries(rb_next(nd)); + nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); if (nd == NULL) break; --offset; @@ -931,7 +958,8 @@ do_offset: } } - nd = hists__filter_prev_entries(rb_prev(nd)); + nd = hists__filter_prev_entries(rb_prev(nd), + hb->min_pcnt); if (nd == NULL) break; ++offset; @@ -1069,27 +1097,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, struct hist_entry *he, FILE *fp) { char s[8192]; - double percent; int printed = 0; char folded_sign = ' '; + struct perf_hpp hpp = { + .buf = s, + .size = sizeof(s), + }; + struct perf_hpp_fmt *fmt; + bool first = true; + int ret; if (symbol_conf.use_callchain) folded_sign = hist_entry__folded(he); - hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); - percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; - if (symbol_conf.use_callchain) printed += fprintf(fp, "%c ", folded_sign); - printed += fprintf(fp, " %5.2f%%", percent); - - if (symbol_conf.show_nr_samples) - printed += fprintf(fp, " %11u", he->stat.nr_events); + perf_hpp__for_each_format(fmt) { + if (perf_hpp__should_skip(fmt)) + continue; - if (symbol_conf.show_total_period) - printed += fprintf(fp, " %12" PRIu64, he->stat.period); + if (!first) { + ret = scnprintf(hpp.buf, hpp.size, " "); + advance_hpp(&hpp, ret); + } else + first = false; + ret = fmt->entry(fmt, &hpp, he); + advance_hpp(&hpp, ret); + } printed += fprintf(fp, "%s\n", rtrim(s)); if (folded_sign == '-') @@ -1100,14 +1136,15 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) { - struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries)); + struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), + browser->min_pcnt); int printed = 0; while (nd) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); printed += hist_browser__fprintf_entry(browser, h, fp); - nd = hists__filter_entries(rb_next(nd)); + nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); } return printed; @@ -1156,10 +1193,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists) browser->b.refresh = hist_browser__refresh; browser->b.seek = ui_browser__hists_seek; browser->b.use_navkeypressed = true; - if (sort__branch_mode == 1) - browser->has_symbols = sort_sym_from.list.next != NULL; - else - browser->has_symbols = sort_sym.list.next != NULL; } return browser; @@ -1193,15 +1226,25 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, char buf[512]; size_t buflen = sizeof(buf); - if (symbol_conf.event_group && evsel->nr_members > 1) { + if (symbol_conf.filter_relative) { + nr_samples = hists->stats.nr_non_filtered_samples; + nr_events = hists->stats.total_non_filtered_period; + } + + if (perf_evsel__is_group_event(evsel)) { struct perf_evsel *pos; perf_evsel__group_desc(evsel, buf, buflen); ev_name = buf; for_each_group_member(pos, evsel) { - nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; - nr_events += pos->hists.stats.total_period; + if (symbol_conf.filter_relative) { + nr_samples += pos->hists.stats.nr_non_filtered_samples; + nr_events += pos->hists.stats.total_non_filtered_period; + } else { + nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + nr_events += pos->hists.stats.total_period; + } } } @@ -1217,8 +1260,8 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, if (thread) printed += scnprintf(bf + printed, size - printed, ", Thread: %s(%d)", - (thread->comm_set ? thread->comm : ""), - thread->pid); + (thread->comm_set ? thread__comm_str(thread) : ""), + thread->tid); if (dso) printed += scnprintf(bf + printed, size - printed, ", DSO: %s", dso->short_name); @@ -1229,10 +1272,8 @@ static inline void free_popup_options(char **options, int n) { int i; - for (i = 0; i < n; ++i) { - free(options[i]); - options[i] = NULL; - } + for (i = 0; i < n; ++i) + zfree(&options[i]); } /* Check whether the browser is for 'top' or 'report' */ @@ -1291,7 +1332,7 @@ static int switch_data_file(void) abs_path[nr_options] = strdup(path); if (!abs_path[nr_options]) { - free(options[nr_options]); + zfree(&options[nr_options]); ui__warning("Can't search all data files due to memory shortage.\n"); fclose(file); break; @@ -1330,11 +1371,29 @@ close_file_and_continue: return ret; } +static void hist_browser__update_nr_entries(struct hist_browser *hb) +{ + u64 nr_entries = 0; + struct rb_node *nd = rb_first(&hb->hists->entries); + + if (hb->min_pcnt == 0) { + hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; + return; + } + + while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { + nr_entries++; + nd = rb_next(nd); + } + + hb->nr_non_filtered_entries = nr_entries; +} static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, const char *helpline, const char *ev_name, bool left_exits, struct hist_browser_timer *hbt, + float min_pcnt, struct perf_session_env *env) { struct hists *hists = &evsel->hists; @@ -1348,9 +1407,45 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, char script_opt[64]; int delay_secs = hbt ? hbt->refresh : 0; +#define HIST_BROWSER_HELP_COMMON \ + "h/?/F1 Show this window\n" \ + "UP/DOWN/PGUP\n" \ + "PGDN/SPACE Navigate\n" \ + "q/ESC/CTRL+C Exit browser\n\n" \ + "For multiple event sessions:\n\n" \ + "TAB/UNTAB Switch events\n\n" \ + "For symbolic views (--sort has sym):\n\n" \ + "-> Zoom into DSO/Threads & Annotate current symbol\n" \ + "<- Zoom out\n" \ + "a Annotate current symbol\n" \ + "C Collapse all callchains\n" \ + "d Zoom into current DSO\n" \ + "E Expand all callchains\n" \ + "F Toggle percentage of filtered entries\n" \ + + /* help messages are sorted by lexical order of the hotkey */ + const char report_help[] = HIST_BROWSER_HELP_COMMON + "i Show header information\n" + "P Print histograms to perf.hist.N\n" + "r Run available scripts\n" + "s Switch to another data file in PWD\n" + "t Zoom into current Thread\n" + "V Verbose (DSO names in callchains, etc)\n" + "/ Filter symbol by name"; + const char top_help[] = HIST_BROWSER_HELP_COMMON + "P Print histograms to perf.hist.N\n" + "t Zoom into current Thread\n" + "V Verbose (DSO names in callchains, etc)\n" + "/ Filter symbol by name"; + if (browser == NULL) return -1; + if (min_pcnt) { + browser->min_pcnt = min_pcnt; + hist_browser__update_nr_entries(browser); + } + fstack = pstack__new(2); if (fstack == NULL) goto out; @@ -1387,7 +1482,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, */ goto out_free_stack; case 'a': - if (!browser->has_symbols) { + if (!sort__has_sym) { ui_browser__warning(&browser->b, delay_secs * 2, "Annotation is only available for symbolic views, " "include \"sym*\" in --sort to use it."); @@ -1427,29 +1522,19 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (is_report_browser(hbt)) goto do_data_switch; continue; + case 'i': + /* env->arch is NULL for live-mode (i.e. perf top) */ + if (env->arch) + tui__header_window(env); + continue; + case 'F': + symbol_conf.filter_relative ^= 1; + continue; case K_F1: case 'h': case '?': ui_browser__help_window(&browser->b, - "h/?/F1 Show this window\n" - "UP/DOWN/PGUP\n" - "PGDN/SPACE Navigate\n" - "q/ESC/CTRL+C Exit browser\n\n" - "For multiple event sessions:\n\n" - "TAB/UNTAB Switch events\n\n" - "For symbolic views (--sort has sym):\n\n" - "-> Zoom into DSO/Threads & Annotate current symbol\n" - "<- Zoom out\n" - "a Annotate current symbol\n" - "C Collapse all callchains\n" - "E Expand all callchains\n" - "d Zoom into current DSO\n" - "t Zoom into current Thread\n" - "r Run available scripts('perf report' only)\n" - "s Switch to another data file in PWD ('perf report' only)\n" - "P Print histograms to perf.hist.N\n" - "V Verbose (DSO names in callchains, etc)\n" - "/ Filter symbol by name"); + is_report_browser(hbt) ? report_help : top_help); continue; case K_ENTER: case K_RIGHT: @@ -1486,10 +1571,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; } - if (!browser->has_symbols) + if (!sort__has_sym) goto add_exit_option; - if (sort__branch_mode == 1) { + if (sort__mode == SORT_MODE__BRANCH) { bi = browser->he_selection->branch_info; if (browser->selection != NULL && bi && @@ -1509,20 +1594,25 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, bi->to.sym->name) > 0) annotate_t = nr_options++; } else { - if (browser->selection != NULL && browser->selection->sym != NULL && - !browser->selection->map->dso->annotate_warned && - asprintf(&options[nr_options], "Annotate %s", - browser->selection->sym->name) > 0) - annotate = nr_options++; + !browser->selection->map->dso->annotate_warned) { + struct annotation *notes; + + notes = symbol__annotation(browser->selection->sym); + + if (notes->src && + asprintf(&options[nr_options], "Annotate %s", + browser->selection->sym->name) > 0) + annotate = nr_options++; + } } if (thread != NULL && asprintf(&options[nr_options], "Zoom %s %s(%d) thread", (browser->hists->thread_filter ? "out of" : "into"), - (thread->comm_set ? thread->comm : ""), - thread->pid) > 0) + (thread->comm_set ? thread__comm_str(thread) : ""), + thread->tid) > 0) zoom_thread = nr_options++; if (dso != NULL && @@ -1541,7 +1631,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, struct symbol *sym; if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", - browser->he_selection->thread->comm) > 0) + thread__comm_str(browser->he_selection->thread)) > 0) scripts_comm = nr_options++; sym = browser->he_selection->ms.sym; @@ -1572,6 +1662,7 @@ retry_popup_menu: if (choice == annotate || choice == annotate_t || choice == annotate_f) { struct hist_entry *he; + struct annotation *notes; int err; do_annotate: if (!objdump_path && perf_session_env__lookup_objdump(env)) @@ -1595,11 +1686,15 @@ do_annotate: he->ms.map = he->branch_info->to.map; } + notes = symbol__annotation(he->ms.sym); + if (!notes->src) + continue; + /* * Don't let this be freed, say, by hists__decay_entry. */ he->used = true; - err = hist_entry__tui_annotate(he, evsel->idx, hbt); + err = hist_entry__tui_annotate(he, evsel, hbt); he->used = false; /* * offer option to annotate the other branch source or target @@ -1622,14 +1717,14 @@ zoom_dso: zoom_out_dso: ui_helpline__pop(); browser->hists->dso_filter = NULL; - sort_dso.elide = false; + perf_hpp__set_elide(HISTC_DSO, false); } else { if (dso == NULL) continue; ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", dso->kernel ? "the Kernel" : dso->short_name); browser->hists->dso_filter = dso; - sort_dso.elide = true; + perf_hpp__set_elide(HISTC_DSO, true); pstack__push(fstack, &browser->hists->dso_filter); } hists__filter_by_dso(hists); @@ -1641,13 +1736,13 @@ zoom_thread: zoom_out_thread: ui_helpline__pop(); browser->hists->thread_filter = NULL; - sort_thread.elide = false; + perf_hpp__set_elide(HISTC_THREAD, false); } else { ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", - thread->comm_set ? thread->comm : "", - thread->pid); + thread->comm_set ? thread__comm_str(thread) : "", + thread->tid); browser->hists->thread_filter = thread; - sort_thread.elide = true; + perf_hpp__set_elide(HISTC_THREAD, false); pstack__push(fstack, &browser->hists->thread_filter); } hists__filter_by_thread(hists); @@ -1660,7 +1755,7 @@ do_scripts: memset(script_opt, 0, 64); if (choice == scripts_comm) - sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm); + sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); if (choice == scripts_symbol) sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); @@ -1690,6 +1785,7 @@ struct perf_evsel_menu { struct ui_browser b; struct perf_evsel *selection; bool lost_events, lost_events_warned; + float min_pcnt; struct perf_session_env *env; }; @@ -1709,7 +1805,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : HE_COLORSET_NORMAL); - if (symbol_conf.event_group && evsel->nr_members > 1) { + if (perf_evsel__is_group_event(evsel)) { struct perf_evsel *pos; ev_name = perf_evsel__group_name(evsel); @@ -1783,20 +1879,21 @@ browse_hists: ev_name = perf_evsel__name(pos); key = perf_evsel__hists_browse(pos, nr_events, help, ev_name, true, hbt, + menu->min_pcnt, menu->env); ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: if (pos->node.next == &evlist->entries) - pos = list_entry(evlist->entries.next, struct perf_evsel, node); + pos = perf_evlist__first(evlist); else - pos = list_entry(pos->node.next, struct perf_evsel, node); + pos = perf_evsel__next(pos); goto browse_hists; case K_UNTAB: if (pos->node.prev == &evlist->entries) - pos = list_entry(evlist->entries.prev, struct perf_evsel, node); + pos = perf_evlist__last(evlist); else - pos = list_entry(pos->node.prev, struct perf_evsel, node); + pos = perf_evsel__prev(pos); goto browse_hists; case K_ESC: if (!ui_browser__dialog_yesno(&menu->b, @@ -1830,7 +1927,7 @@ out: return key; } -static bool filter_group_entries(struct ui_browser *self __maybe_unused, +static bool filter_group_entries(struct ui_browser *browser __maybe_unused, void *entry) { struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); @@ -1844,6 +1941,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused, static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, int nr_entries, const char *help, struct hist_browser_timer *hbt, + float min_pcnt, struct perf_session_env *env) { struct perf_evsel *pos; @@ -1857,12 +1955,13 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, .nr_entries = nr_entries, .priv = evlist, }, + .min_pcnt = min_pcnt, .env = env, }; ui_helpline__push("Press ESC to exit"); - list_for_each_entry(pos, &evlist->entries, node) { + evlist__for_each(evlist, pos) { const char *ev_name = perf_evsel__name(pos); size_t line_len = strlen(ev_name) + 7; @@ -1875,32 +1974,34 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, struct hist_browser_timer *hbt, + float min_pcnt, struct perf_session_env *env) { int nr_entries = evlist->nr_entries; single_entry: if (nr_entries == 1) { - struct perf_evsel *first = list_entry(evlist->entries.next, - struct perf_evsel, node); + struct perf_evsel *first = perf_evlist__first(evlist); const char *ev_name = perf_evsel__name(first); return perf_evsel__hists_browse(first, nr_entries, help, - ev_name, false, hbt, env); + ev_name, false, hbt, min_pcnt, + env); } if (symbol_conf.event_group) { struct perf_evsel *pos; nr_entries = 0; - list_for_each_entry(pos, &evlist->entries, node) + evlist__for_each(evlist, pos) { if (perf_evsel__is_group_leader(pos)) nr_entries++; + } if (nr_entries == 1) goto single_entry; } return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, - hbt, env); + hbt, min_pcnt, env); } |
