From 81cce8de9437be9234f651be1f03e596c1b1a79a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Oct 2011 19:11:32 -0300 Subject: perf browsers: Add live mode to the hists, annotate browsers This allows passing a timer to be run periodically, which will update the hists tree that then gers refreshed on the screen, just like the Live mode (symbol entries, annotation) we already have in 'perf top --tui'. Will be used by the new hist_entry/hists based 'top' tool. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2r44qd8oe4sagzcgoikl8qzc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 105 +++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 36 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 5d767c622dfc..6244d19bd1f2 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -24,8 +24,14 @@ struct hist_browser { struct hists *hists; struct hist_entry *he_selection; struct map_symbol *selection; + const struct thread *thread_filter; + const struct dso *dso_filter; }; +static int hists__browser_title(struct hists *self, char *bf, size_t size, + const char *ev_name, const struct dso *dso, + const struct thread *thread); + static void hist_browser__refresh_dimensions(struct hist_browser *self) { /* 3 == +/- toggle symbol before actual hist_entry rendering */ @@ -290,9 +296,12 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold) ui_browser__reset_index(&self->b); } -static int hist_browser__run(struct hist_browser *self, const char *title) +static int hist_browser__run(struct hist_browser *self, const char *ev_name, + void(*timer)(void *arg), void *arg, int delay_secs) { int key; + int delay_msecs = delay_secs * 1000; + char title[160]; int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, }; @@ -301,17 +310,30 @@ static int hist_browser__run(struct hist_browser *self, const char *title) self->b.nr_entries = self->hists->nr_entries; hist_browser__refresh_dimensions(self); + hists__browser_title(self->hists, title, sizeof(title), ev_name, + self->dso_filter, self->thread_filter); if (ui_browser__show(&self->b, title, "Press '?' for help on key bindings") < 0) return -1; + if (timer != NULL) + newtFormSetTimer(self->b.form, delay_msecs); + ui_browser__add_exit_keys(&self->b, exit_keys); while (1) { key = ui_browser__run(&self->b); switch (key) { + case -1: + /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ + timer(arg); + hists__browser_title(self->hists, title, sizeof(title), + ev_name, self->dso_filter, + self->thread_filter); + ui_browser__show_title(&self->b, title); + continue; case 'D': { /* Debug */ static int seq; struct hist_entry *h = rb_entry(self->b.top, @@ -805,14 +827,13 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, static int perf_evsel__hists_browse(struct perf_evsel *evsel, const char *helpline, const char *ev_name, - bool left_exits) + bool left_exits, + void(*timer)(void *arg), void *arg, + int delay_secs) { struct hists *self = &evsel->hists; struct hist_browser *browser = hist_browser__new(self); struct pstack *fstack; - const struct thread *thread_filter = NULL; - const struct dso *dso_filter = NULL; - char msg[160]; int key = -1; if (browser == NULL) @@ -824,8 +845,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, ui_helpline__push(helpline); - hists__browser_title(self, msg, sizeof(msg), ev_name, - dso_filter, thread_filter); while (1) { const struct thread *thread = NULL; const struct dso *dso = NULL; @@ -834,7 +853,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, annotate = -2, zoom_dso = -2, zoom_thread = -2, browse_map = -2; - key = hist_browser__run(browser, msg); + key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); if (browser->he_selection != NULL) { thread = hist_browser__selected_thread(browser); @@ -889,9 +908,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, continue; } top = pstack__pop(fstack); - if (top == &dso_filter) + if (top == &browser->dso_filter) goto zoom_out_dso; - if (top == &thread_filter) + if (top == &browser->thread_filter) goto zoom_out_thread; continue; } @@ -913,14 +932,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, if (thread != NULL && asprintf(&options[nr_options], "Zoom %s %s(%d) thread", - (thread_filter ? "out of" : "into"), + (browser->thread_filter ? "out of" : "into"), (thread->comm_set ? thread->comm : ""), thread->pid) > 0) zoom_thread = nr_options++; if (dso != NULL && asprintf(&options[nr_options], "Zoom %s %s DSO", - (dso_filter ? "out of" : "into"), + (browser->dso_filter ? "out of" : "into"), (dso->kernel ? "the Kernel" : dso->short_name)) > 0) zoom_dso = nr_options++; @@ -949,45 +968,42 @@ do_annotate: if (he == NULL) continue; - hist_entry__tui_annotate(he, evsel->idx); + hist_entry__tui_annotate(he, evsel->idx, + timer, arg, delay_secs); } else if (choice == browse_map) map__browse(browser->selection->map); else if (choice == zoom_dso) { zoom_dso: - if (dso_filter) { - pstack__remove(fstack, &dso_filter); + if (browser->dso_filter) { + pstack__remove(fstack, &browser->dso_filter); zoom_out_dso: ui_helpline__pop(); - dso_filter = NULL; + browser->dso_filter = NULL; } 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); - dso_filter = dso; - pstack__push(fstack, &dso_filter); + browser->dso_filter = dso; + pstack__push(fstack, &browser->dso_filter); } - hists__filter_by_dso(self, dso_filter); - hists__browser_title(self, msg, sizeof(msg), ev_name, - dso_filter, thread_filter); + hists__filter_by_dso(self, browser->dso_filter); hist_browser__reset(browser); } else if (choice == zoom_thread) { zoom_thread: - if (thread_filter) { - pstack__remove(fstack, &thread_filter); + if (browser->thread_filter) { + pstack__remove(fstack, &browser->thread_filter); zoom_out_thread: ui_helpline__pop(); - thread_filter = NULL; + browser->thread_filter = NULL; } else { ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", thread->comm_set ? thread->comm : "", thread->pid); - thread_filter = thread; - pstack__push(fstack, &thread_filter); + browser->thread_filter = thread; + pstack__push(fstack, &browser->thread_filter); } - hists__filter_by_thread(self, thread_filter); - hists__browser_title(self, msg, sizeof(msg), ev_name, - dso_filter, thread_filter); + hists__filter_by_thread(self, browser->thread_filter); hist_browser__reset(browser); } } @@ -1026,9 +1042,11 @@ static void perf_evsel_menu__write(struct ui_browser *browser, menu->selection = evsel; } -static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) +static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help, + void(*timer)(void *arg), void *arg, int delay_secs) { int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; + int delay_msecs = delay_secs * 1000; struct perf_evlist *evlist = menu->b.priv; struct perf_evsel *pos; const char *ev_name, *title = "Available samples"; @@ -1038,20 +1056,29 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) "ESC: exit, ENTER|->: Browse histograms") < 0) return -1; + if (timer != NULL) + newtFormSetTimer(menu->b.form, delay_msecs); + ui_browser__add_exit_keys(&menu->b, exit_keys); while (1) { key = ui_browser__run(&menu->b); switch (key) { + case -1: + /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ + timer(arg); + continue; case NEWT_KEY_RIGHT: case NEWT_KEY_ENTER: if (!menu->selection) continue; pos = menu->selection; + perf_evlist__set_selected(evlist, pos); browse_hists: ev_name = event_name(pos); - key = perf_evsel__hists_browse(pos, help, ev_name, true); + key = perf_evsel__hists_browse(pos, help, ev_name, true, + timer, arg, delay_secs); ui_browser__show_title(&menu->b, title); break; case NEWT_KEY_LEFT: @@ -1091,7 +1118,9 @@ out: } static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, - const char *help) + const char *help, + void(*timer)(void *arg), void *arg, + int delay_secs) { struct perf_evsel *pos; struct perf_evsel_menu menu = { @@ -1121,18 +1150,22 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, pos->name = strdup(ev_name); } - return perf_evsel_menu__run(&menu, help); + return perf_evsel_menu__run(&menu, help, timer, arg, delay_secs); } -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) +int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + void(*timer)(void *arg), void *arg, + int delay_secs) { if (evlist->nr_entries == 1) { struct perf_evsel *first = list_entry(evlist->entries.next, struct perf_evsel, node); const char *ev_name = event_name(first); - return perf_evsel__hists_browse(first, help, ev_name, false); + return perf_evsel__hists_browse(first, help, ev_name, false, + timer, arg, delay_secs); } - return __perf_evlist__tui_browse_hists(evlist, help); + return __perf_evlist__tui_browse_hists(evlist, help, + timer, arg, delay_secs); } -- cgit v1.2.3 From 34958544b3da17e98d98d7b872c6516995ad66bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Oct 2011 19:35:54 -0300 Subject: perf annotate browser: Allow navigation to called functions I.e. when in the annotate TUI window, if Enter is pressed over an assembly line with a 'callq' it will try to open another TUI window with that symbol. This is just a proof of concept and works only on x86_64, more work is needed to support kernel modules, userland, other arches, etc, but should already be useful as-is. Suggested-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-opyvskw5na3qdmkv8vxi3zbr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 9 +++-- tools/perf/util/annotate.h | 2 +- tools/perf/util/hist.h | 4 +- tools/perf/util/ui/browsers/annotate.c | 69 ++++++++++++++++++++++++++++------ tools/perf/util/ui/browsers/hists.c | 20 ++++++---- 5 files changed, 79 insertions(+), 25 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 39e3d382b2d8..24db9d2db7b4 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -114,7 +114,8 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) print_line, full_paths, 0, 0); } -static void hists__find_annotations(struct hists *self, int evidx) +static void hists__find_annotations(struct hists *self, int evidx, + int nr_events) { struct rb_node *nd = rb_first(&self->entries), *next; int key = KEY_RIGHT; @@ -137,7 +138,8 @@ find_next: } if (use_browser > 0) { - key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); + key = hist_entry__tui_annotate(he, evidx, nr_events, + NULL, NULL, 0); switch (key) { case KEY_RIGHT: next = rb_next(nd); @@ -215,7 +217,8 @@ static int __cmd_annotate(void) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); - hists__find_annotations(hists, pos->idx); + hists__find_annotations(hists, pos->idx, + session->evlist->nr_entries); } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index aafbc7e9a9ba..d9072523d342 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -99,7 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used, } #else int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - void(*timer)(void *arg), void *arg, + int nr_events, void(*timer)(void *arg), void *arg, int delay_secs); #endif diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f87677bfaff9..7ea1e560e008 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -110,7 +110,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, } static inline int hist_entry__tui_annotate(struct hist_entry *self __used, - int evidx __used, + int evidx __used, int nr_events __used, void(*timer)(void *arg) __used, void *arg __used, int delay_secs __used); { @@ -120,7 +120,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, #define KEY_RIGHT -2 #else #include -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs); #define KEY_LEFT NEWT_KEY_LEFT diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 76c1d083aa94..77421bab8fdd 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -20,6 +20,7 @@ struct annotate_browser { struct ui_browser b; struct rb_root entries; struct rb_node *curr_hot; + struct objdump_line *selection; }; struct objdump_line_rb_node { @@ -36,6 +37,7 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) static void annotate_browser__write(struct ui_browser *self, void *entry, int row) { + struct annotate_browser *ab = container_of(self, struct annotate_browser, b); struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); bool current_entry = ui_browser__is_current_entry(self, row); int width = self->width; @@ -58,6 +60,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!current_entry) ui_browser__set_color(self, HE_COLORSET_CODE); + else + ab->selection = ol; } static double objdump_line__calc_percent(struct objdump_line *self, @@ -141,7 +145,8 @@ static void annotate_browser__set_top(struct annotate_browser *self, static void annotate_browser__calc_percent(struct annotate_browser *browser, int evidx) { - struct symbol *sym = browser->b.priv; + struct map_symbol *ms = browser->b.priv; + struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); struct objdump_line *pos; @@ -164,17 +169,18 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, } static int annotate_browser__run(struct annotate_browser *self, int evidx, - void(*timer)(void *arg) __used, void *arg __used, - int delay_secs) + int nr_events, void(*timer)(void *arg), + void *arg, int delay_secs) { struct rb_node *nd = NULL; - struct symbol *sym = self->b.priv; + struct map_symbol *ms = self->b.priv; + struct symbol *sym = ms->sym; /* * RIGHT To allow builtin-annotate to cycle thru multiple symbols by * examining the exit key for this function. */ int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, - NEWT_KEY_RIGHT, 0 }; + NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 }; int key; if (ui_browser__show(&self->b, sym->name, @@ -238,6 +244,42 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, case 'H': nd = self->curr_hot; break; + case NEWT_KEY_ENTER: + if (self->selection != NULL) { + char *s = strstr(self->selection->line, "callq "); + struct annotation *notes; + struct symbol *target; + u64 ip; + + if (s == NULL) + continue; + + s = strchr(s, ' '); + if (s++ == NULL) + continue; + + ip = strtoull(s, NULL, 16); + ip = ms->map->map_ip(ms->map, ip); + target = map__find_symbol(ms->map, ip, NULL); + if (target == NULL) + continue; + + notes = symbol__annotation(target); + pthread_mutex_lock(¬es->lock); + + if (notes->src == NULL && + symbol__alloc_hist(target, nr_events) < 0) { + pthread_mutex_unlock(¬es->lock); + ui__warning("Not enough memory for annotating '%s' symbol!\n", + target->name); + continue; + } + + pthread_mutex_unlock(¬es->lock); + symbol__tui_annotate(target, ms->map, evidx, nr_events, + timer, arg, delay_secs); + } + break; default: goto out; } @@ -250,25 +292,29 @@ out: return key; } -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs) { - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, + return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, timer, arg, delay_secs); } int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - void(*timer)(void *arg), void *arg, - int delay_secs) + int nr_events, void(*timer)(void *arg), void *arg, + int delay_secs) { struct objdump_line *pos, *n; struct annotation *notes; + struct map_symbol ms = { + .map = map, + .sym = sym, + }; struct annotate_browser browser = { .b = { .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, - .priv = sym, + .priv = &ms, }, }; int ret; @@ -300,7 +346,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); + ret = annotate_browser__run(&browser, evidx, nr_events, + timer, arg, delay_secs); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); objdump_line__free(pos); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 6244d19bd1f2..f0515cbabda5 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -825,7 +825,7 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, return printed; } -static int perf_evsel__hists_browse(struct perf_evsel *evsel, +static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, const char *helpline, const char *ev_name, bool left_exits, void(*timer)(void *arg), void *arg, @@ -968,7 +968,7 @@ do_annotate: if (he == NULL) continue; - hist_entry__tui_annotate(he, evsel->idx, + hist_entry__tui_annotate(he, evsel->idx, nr_events, timer, arg, delay_secs); } else if (choice == browse_map) map__browse(browser->selection->map); @@ -1042,7 +1042,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, menu->selection = evsel; } -static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help, +static int perf_evsel_menu__run(struct perf_evsel_menu *menu, + int nr_events, const char *help, void(*timer)(void *arg), void *arg, int delay_secs) { int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; @@ -1077,8 +1078,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help, perf_evlist__set_selected(evlist, pos); browse_hists: ev_name = event_name(pos); - key = perf_evsel__hists_browse(pos, help, ev_name, true, - timer, arg, delay_secs); + key = perf_evsel__hists_browse(pos, nr_events, help, + ev_name, true, timer, + arg, delay_secs); ui_browser__show_title(&menu->b, title); break; case NEWT_KEY_LEFT: @@ -1150,7 +1152,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, pos->name = strdup(ev_name); } - return perf_evsel_menu__run(&menu, help, timer, arg, delay_secs); + return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, + arg, delay_secs); } int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, @@ -1162,8 +1165,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, struct perf_evsel *first = list_entry(evlist->entries.next, struct perf_evsel, node); const char *ev_name = event_name(first); - return perf_evsel__hists_browse(first, help, ev_name, false, - timer, arg, delay_secs); + return perf_evsel__hists_browse(first, evlist->nr_entries, help, + ev_name, false, timer, arg, + delay_secs); } return __perf_evlist__tui_browse_hists(evlist, help, -- cgit v1.2.3 From 724c9c9f20c7a0ebd9a728391f5adcfd4a76628b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Oct 2011 10:36:35 -0300 Subject: perf hists browser: Don't offer symbol actions when symbols not on --sort Removing all the entries that only apply to symbols from the menu. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7bap0cy2fxtorlj5hgsp48m1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index f0515cbabda5..b7901099eedb 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -26,6 +26,7 @@ struct hist_browser { struct map_symbol *selection; const struct thread *thread_filter; const struct dso *dso_filter; + bool has_symbols; }; static int hists__browser_title(struct hists *self, char *bf, size_t size, @@ -302,9 +303,9 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, int key; int delay_msecs = delay_secs * 1000; char title[160]; - int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', - NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, - NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, }; + int sym_exit_keys[] = { 'a', 'h', 'C', 'd', 'E', 't', 0, }; + int exit_keys[] = { '?', 'h', 'D', NEWT_KEY_LEFT, NEWT_KEY_RIGHT, + NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, }; self->b.entries = &self->hists->entries; self->b.nr_entries = self->hists->nr_entries; @@ -321,6 +322,8 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, newtFormSetTimer(self->b.form, delay_msecs); ui_browser__add_exit_keys(&self->b, exit_keys); + if (self->has_symbols) + ui_browser__add_exit_keys(&self->b, sym_exit_keys); while (1) { key = ui_browser__run(&self->b); @@ -783,6 +786,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists) self->hists = hists; self->b.refresh = hist_browser__refresh; self->b.seek = ui_browser__hists_seek; + self->has_symbols = sort_sym.list.next != NULL; } return self; @@ -881,16 +885,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, case NEWT_KEY_F1: case 'h': case '?': - ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" + ui__help_window("h/?/F1 Show this window\n" + "TAB/UNTAB Switch events\n" + "q/CTRL+C Exit browser\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" - "h/?/F1 Show this window\n" "C Collapse all callchains\n" "E Expand all callchains\n" "d Zoom into current DSO\n" - "t Zoom into current Thread\n" - "TAB/UNTAB Switch events\n" - "q/CTRL+C Exit browser"); + "t Zoom into current Thread\n"); continue; case NEWT_KEY_ENTER: case NEWT_KEY_RIGHT: @@ -923,6 +928,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, goto out_free_stack; } + if (!browser->has_symbols) + goto add_exit_option; + if (browser->selection != NULL && browser->selection->sym != NULL && !browser->selection->map->dso->annotate_warned && @@ -947,7 +955,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, browser->selection->map != NULL && asprintf(&options[nr_options], "Browse map details") > 0) browse_map = nr_options++; - +add_exit_option: options[nr_options++] = (char *)"Exit"; choice = ui__popup_menu(nr_options, options); -- cgit v1.2.3 From 7d16320e2315db434b28854c08677e0d15b604f1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Oct 2011 10:46:45 -0300 Subject: perf hists browser: Fix TAB/UNTAB use with multiple events When requesting multiple events, say: # perf top -e instructions -e cycles -e cache-misses The first screen lets the user chose what to see first, then to switch one can either use the left key to get back to the event menu or simply use TAB to go the next and shift+TAB to go the prev. When using TAB/UNTAB the call to perf_evlist__set_selected(event) was missing, fix it. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3xqqh3fwmt914gg43frey14y@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index b7901099eedb..ef6ccefad432 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1107,12 +1107,14 @@ browse_hists: pos = list_entry(evlist->entries.next, struct perf_evsel, node); else pos = list_entry(pos->node.next, struct perf_evsel, node); + perf_evlist__set_selected(evlist, pos); goto browse_hists; case NEWT_KEY_UNTAB: if (pos->node.prev == &evlist->entries) pos = list_entry(evlist->entries.prev, struct perf_evsel, node); else pos = list_entry(pos->node.prev, struct perf_evsel, node); + perf_evlist__set_selected(evlist, pos); goto browse_hists; case 'q': case CTRL('c'): -- cgit v1.2.3 From be83f5ed6bc46cd89b4a102b6e341ecddf7abf91 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Oct 2011 10:56:05 -0300 Subject: perf hists browser: Update the browser.nr_entries after the timer Previously the hist_browser dealt with a static tree of entries, now it needs to update the nr_entries in the browser after the timer runs. A better solution will come when moving using another thread for the collapse_resort, etc, but for now this is ok. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-9eno2iq55sjr4iyo899buzaw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index ef6ccefad432..e64d9527f14e 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -332,6 +332,13 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, case -1: /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ timer(arg); + /* + * The timer may have changed the number of entries. + * XXX: Find better way to keep this in synch, probably + * removing this timer function altogether and just sync + * using the hists->lock... + */ + self->b.nr_entries = self->hists->nr_entries; hists__browser_title(self->hists, title, sizeof(title), ev_name, self->dso_filter, self->thread_filter); -- cgit v1.2.3 From 900e14a8f5a49e987790b93c7906989b22075f1b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Oct 2011 16:15:39 -0300 Subject: perf hists browser: Recalculate browser pointers after resort/decay In browsers that access dynamic underlying data structures, like in the hists browser and its hist_entry rb_tree, we need to revalidate any reference to the underlying data structure, because they can have gone away, decayed. This fixes a problem where after a while the top entries get behind the top of the screen, i.e. the top_idx stays at 0, which means it is at the first entry in the rb_tree when in fact it wasn't because the browser->top didn't got revalidated after the timer ran and the underlying data structure got updated. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-mhje66qssdko24q67a2lhlho@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browser.c | 23 +++++++++++++++++++++++ tools/perf/util/ui/browser.h | 1 + tools/perf/util/ui/browsers/hists.c | 9 ++------- 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 611219f80680..5911bba63858 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -230,6 +230,29 @@ int ui_browser__refresh(struct ui_browser *self) return 0; } +/* + * Here we're updating nr_entries _after_ we started browsing, i.e. we have to + * forget about any reference to any entry in the underlying data structure, + * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser + * after an output_resort and hist decay. + */ +void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) +{ + off_t offset = nr_entries - browser->nr_entries; + + browser->nr_entries = nr_entries; + + if (offset < 0) { + if (browser->top_idx < (u64)-offset) + offset = -browser->top_idx; + + browser->index += offset; + browser->top_idx += offset; + } + + browser->seek(browser, browser->top_idx, SEEK_SET); +} + int ui_browser__run(struct ui_browser *self) { struct newtExitStruct es; diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index fc63dda10910..d42be43ac0e8 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -41,6 +41,7 @@ int ui_browser__show(struct ui_browser *self, const char *title, void ui_browser__hide(struct ui_browser *self); int ui_browser__refresh(struct ui_browser *self); int ui_browser__run(struct ui_browser *self); +void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index e64d9527f14e..9ece84353538 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -332,13 +332,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, case -1: /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ timer(arg); - /* - * The timer may have changed the number of entries. - * XXX: Find better way to keep this in synch, probably - * removing this timer function altogether and just sync - * using the hists->lock... - */ - self->b.nr_entries = self->hists->nr_entries; + ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); hists__browser_title(self->hists, title, sizeof(title), ev_name, self->dso_filter, self->thread_filter); @@ -985,6 +979,7 @@ do_annotate: hist_entry__tui_annotate(he, evsel->idx, nr_events, timer, arg, delay_secs); + ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); } else if (choice == browse_map) map__browse(browser->selection->map); else if (choice == zoom_dso) { -- cgit v1.2.3 From df71d95f86ec7310722f96b6902699f3fe30b439 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Oct 2011 08:01:33 -0300 Subject: perf hists: Don't free decayed entries if in the annotation browser Just let it there till the user exits the annotation browser. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-nmaxuzreqhm5k10t2co5sk9a@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 10 ++++++++-- tools/perf/util/sort.h | 1 + tools/perf/util/ui/browsers/hists.c | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 50c8fece1681..9b9d12bbdc1d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -100,6 +100,8 @@ static void hist_entry__decay(struct hist_entry *he) static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) { + if (he->period == 0) + return true; hists->stats.total_period -= he->period; hist_entry__decay(he); hists->stats.total_period += he->period; @@ -114,8 +116,12 @@ void hists__decay_entries(struct hists *hists) while (next) { n = rb_entry(next, struct hist_entry, rb_node); next = rb_next(&n->rb_node); - - if (hists__decay_entry(hists, n)) { + /* + * We may be annotating this, for instance, so keep it here in + * case some it gets new samples, we'll eventually free it when + * the user stops browsing and it agains gets fully decayed. + */ + if (hists__decay_entry(hists, n) && !n->used) { rb_erase(&n->rb_node, &hists->entries); if (sort__need_collapse) diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 03851e301721..3f67ae395752 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -64,6 +64,7 @@ struct hist_entry { bool init_have_children; char level; + bool used; u8 filtered; struct symbol *parent; union { diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 9ece84353538..fdc3c90696dc 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -976,9 +976,13 @@ do_annotate: he = hist_browser__selected_entry(browser); if (he == NULL) continue; - + /* + * Don't let this be freed, say, by hists__decay_entry. + */ + he->used = true; hist_entry__tui_annotate(he, evsel->idx, nr_events, timer, arg, delay_secs); + he->used = false; ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); } else if (choice == browse_map) map__browse(browser->selection->map); -- cgit v1.2.3 From 3af6e33867b3814a73c3f3ba991a13d7304ad23a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Oct 2011 08:52:46 -0300 Subject: perf ui browser: Handle SIGWINCH To do that we needed to stop using newtForm, as we don't want libnewt to catch the xterm resize signal. Remove some more newt calls and instead use the underlying libslang directly. In time tools/perf will use just libslang. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-h1824yjiru5n2ivz4bseizwj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 21 ++++- tools/perf/perf.c | 24 ++++++ tools/perf/perf.h | 2 + tools/perf/util/ui/browser.c | 137 ++++++++++++++++++++++----------- tools/perf/util/ui/browser.h | 6 +- tools/perf/util/ui/browsers/annotate.c | 5 +- tools/perf/util/ui/browsers/hists.c | 12 +-- tools/perf/util/ui/browsers/map.c | 3 +- tools/perf/util/ui/helpline.h | 2 + 9 files changed, 144 insertions(+), 68 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c5aebf6eb746..de3cb1e00f9e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -585,16 +585,31 @@ static void *display_thread(void *arg __used) tc.c_cc[VMIN] = 0; tc.c_cc[VTIME] = 0; + pthread__unblock_sigwinch(); repeat: delay_msecs = top.delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); - do { + while (1) { print_sym_table(); - } while (!poll(&stdin_poll, 1, delay_msecs) == 1); - + /* + * Either timeout expired or we got an EINTR due to SIGWINCH, + * refresh screen in both cases. + */ + switch (poll(&stdin_poll, 1, delay_msecs)) { + case 0: + continue; + case -1: + if (errno == EINTR) + continue; + /* Fall trhu */ + default: + goto process_hotkey; + } + } +process_hotkey: c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); diff --git a/tools/perf/perf.c b/tools/perf/perf.c index ec635b7cc8ea..73d0cac8b67e 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void) debugfs_mntpt[0] = '\0'; } +static void pthread__block_sigwinch(void) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGWINCH); + pthread_sigmask(SIG_BLOCK, &set, NULL); +} + +void pthread__unblock_sigwinch(void) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGWINCH); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); +} + int main(int argc, const char **argv) { const char *cmd; @@ -480,6 +498,12 @@ int main(int argc, const char **argv) * time. */ setup_path(); + /* + * Block SIGWINCH notifications so that the thread that wants it can + * unblock and get syscalls like select interrupted instead of waiting + * forever while the signal goes to some other non interested thread. + */ + pthread__block_sigwinch(); while (1) { static int done_help; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 08b0b5e82a44..914c895510f7 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -183,4 +183,6 @@ struct ip_callchain { extern bool perf_host, perf_guest; extern const char perf_version_string[]; +void pthread__unblock_sigwinch(void); + #endif diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 5911bba63858..05a0f61312d8 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -1,4 +1,7 @@ +#include "../util.h" +#include "../../perf.h" #include "libslang.h" +#include #include "ui.h" #include #include @@ -8,8 +11,8 @@ #include "browser.h" #include "helpline.h" #include "../color.h" -#include "../util.h" -#include + +int newtGetKey(void); static int ui_browser__percent_color(double percent, bool current) { @@ -127,11 +130,8 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) void ui_browser__refresh_dimensions(struct ui_browser *self) { - int cols, rows; - newtGetScreenSize(&cols, &rows); - - self->width = cols - 1; - self->height = rows - 2; + self->width = SLtt_Screen_Cols - 1; + self->height = SLtt_Screen_Rows - 2; self->y = 1; self->x = 0; } @@ -142,9 +142,8 @@ void ui_browser__reset_index(struct ui_browser *self) self->seek(self, 0, SEEK_SET); } -void ui_browser__add_exit_key(struct ui_browser *self, int key) +void ui_browser__add_exit_key(struct ui_browser *browser __used, int key __used) { - newtFormAddHotKey(self->form, key); } void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) @@ -161,7 +160,7 @@ void __ui_browser__show_title(struct ui_browser *browser, const char *title) { SLsmg_gotorc(0, 0); ui_browser__set_color(browser, NEWT_COLORSET_ROOT); - slsmg_write_nstring(title, browser->width); + slsmg_write_nstring(title, browser->width + 1); } void ui_browser__show_title(struct ui_browser *browser, const char *title) @@ -174,57 +173,75 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title) int ui_browser__show(struct ui_browser *self, const char *title, const char *helpline, ...) { + int err; va_list ap; int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP, NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ', NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 }; - if (self->form != NULL) - newtFormDestroy(self->form); - ui_browser__refresh_dimensions(self); - self->form = newtForm(NULL, NULL, 0); - if (self->form == NULL) - return -1; - - self->sb = newtVerticalScrollbar(self->width, 1, self->height, - HE_COLORSET_NORMAL, - HE_COLORSET_SELECTED); - if (self->sb == NULL) - return -1; pthread_mutex_lock(&ui__lock); __ui_browser__show_title(self, title); ui_browser__add_exit_keys(self, keys); - newtFormAddComponent(self->form, self->sb); + self->title = title; + free(self->helpline); + self->helpline = NULL; va_start(ap, helpline); - ui_helpline__vpush(helpline, ap); + err = vasprintf(&self->helpline, helpline, ap); va_end(ap); + if (err > 0) + ui_helpline__push(self->helpline); pthread_mutex_unlock(&ui__lock); - return 0; + return err ? 0 : -1; } -void ui_browser__hide(struct ui_browser *self) +void ui_browser__hide(struct ui_browser *browser __used) { pthread_mutex_lock(&ui__lock); - newtFormDestroy(self->form); - self->form = NULL; ui_helpline__pop(); pthread_mutex_unlock(&ui__lock); } -int ui_browser__refresh(struct ui_browser *self) +static void ui_browser__scrollbar_set(struct ui_browser *browser) +{ + int height = browser->height, h = 0, pct = 0, + col = browser->width, + row = browser->y - 1; + + if (browser->nr_entries > 1) { + pct = ((browser->index * (browser->height - 1)) / + (browser->nr_entries - 1)); + } + + while (h < height) { + ui_browser__gotorc(browser, row++, col); + SLsmg_set_char_set(1); + SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR); + SLsmg_set_char_set(0); + ++h; + } +} + +static int __ui_browser__refresh(struct ui_browser *browser) { int row; + row = browser->refresh(browser); + ui_browser__set_color(browser, HE_COLORSET_NORMAL); + SLsmg_fill_region(browser->y + row, browser->x, + browser->height - row, browser->width, ' '); + ui_browser__scrollbar_set(browser); + + return 0; +} + +int ui_browser__refresh(struct ui_browser *browser) +{ pthread_mutex_lock(&ui__lock); - newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); - row = self->refresh(self); - ui_browser__set_color(self, HE_COLORSET_NORMAL); - SLsmg_fill_region(self->y + row, self->x, - self->height - row, self->width, ' '); + __ui_browser__refresh(browser); pthread_mutex_unlock(&ui__lock); return 0; @@ -253,21 +270,49 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) browser->seek(browser, browser->top_idx, SEEK_SET); } -int ui_browser__run(struct ui_browser *self) +int ui_browser__run(struct ui_browser *self, int delay_secs) { - struct newtExitStruct es; + int err, key; + struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; - if (ui_browser__refresh(self) < 0) - return -1; + pthread__unblock_sigwinch(); while (1) { off_t offset; + fd_set read_set; - newtFormRun(self->form, &es); + pthread_mutex_lock(&ui__lock); + err = __ui_browser__refresh(self); + SLsmg_refresh(); + pthread_mutex_unlock(&ui__lock); + if (err < 0) + break; + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + + if (delay_secs) { + timeout.tv_sec = delay_secs; + timeout.tv_usec = 0; + } - if (es.reason != NEWT_EXIT_HOTKEY) + err = select(1, &read_set, NULL, NULL, ptimeout); + if (err > 0 && FD_ISSET(0, &read_set)) + key = newtGetKey(); + else if (err == 0) break; - switch (es.u.key) { + else { + pthread_mutex_lock(&ui__lock); + SLtt_get_screen_size(); + SLsmg_reinit_smg(); + pthread_mutex_unlock(&ui__lock); + ui_browser__refresh_dimensions(self); + __ui_browser__show_title(self, self->title); + ui_helpline__puts(self->helpline); + continue; + } + + switch (key) { case NEWT_KEY_DOWN: if (self->index == self->nr_entries - 1) break; @@ -324,10 +369,8 @@ int ui_browser__run(struct ui_browser *self) self->seek(self, -offset, SEEK_END); break; default: - return es.u.key; + return key; } - if (ui_browser__refresh(self) < 0) - return -1; } return -1; } @@ -353,13 +396,13 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self) return row; } -static struct newtPercentTreeColors { +static struct ui_browser__colors { const char *topColorFg, *topColorBg; const char *mediumColorFg, *mediumColorBg; const char *normalColorFg, *normalColorBg; const char *selColorFg, *selColorBg; const char *codeColorFg, *codeColorBg; -} defaultPercentTreeColors = { +} ui_browser__default_colors = { "red", "lightgray", "green", "lightgray", "black", "lightgray", @@ -369,7 +412,7 @@ static struct newtPercentTreeColors { void ui_browser__init(void) { - struct newtPercentTreeColors *c = &defaultPercentTreeColors; + struct ui_browser__colors *c = &ui_browser__default_colors; sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index d42be43ac0e8..37d56bfe8fe3 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -2,7 +2,6 @@ #define _PERF_UI_BROWSER_H_ 1 #include -#include #include #include "../types.h" @@ -13,11 +12,12 @@ #define HE_COLORSET_CODE 54 struct ui_browser { - newtComponent form, sb; u64 index, top_idx; void *top, *entries; u16 y, x, width, height; void *priv; + const char *title; + char *helpline; unsigned int (*refresh)(struct ui_browser *self); void (*write)(struct ui_browser *self, void *entry, int row); void (*seek)(struct ui_browser *self, off_t offset, int whence); @@ -40,7 +40,7 @@ int ui_browser__show(struct ui_browser *self, const char *title, const char *helpline, ...); void ui_browser__hide(struct ui_browser *self); int ui_browser__refresh(struct ui_browser *self); -int ui_browser__run(struct ui_browser *self); +int ui_browser__run(struct ui_browser *browser, int delay_secs); void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 674b55e686fd..1967fbf73998 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -196,11 +196,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, nd = self->curr_hot; - if (delay_secs != 0) - newtFormSetTimer(self->b.form, delay_secs * 1000); - while (1) { - key = ui_browser__run(&self->b); + key = ui_browser__run(&self->b, delay_secs); if (delay_secs != 0) { annotate_browser__calc_percent(self, evidx); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index fdc3c90696dc..603d6ee5a0d7 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -301,7 +301,6 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, void(*timer)(void *arg), void *arg, int delay_secs) { int key; - int delay_msecs = delay_secs * 1000; char title[160]; int sym_exit_keys[] = { 'a', 'h', 'C', 'd', 'E', 't', 0, }; int exit_keys[] = { '?', 'h', 'D', NEWT_KEY_LEFT, NEWT_KEY_RIGHT, @@ -318,15 +317,12 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, "Press '?' for help on key bindings") < 0) return -1; - if (timer != NULL) - newtFormSetTimer(self->b.form, delay_msecs); - ui_browser__add_exit_keys(&self->b, exit_keys); if (self->has_symbols) ui_browser__add_exit_keys(&self->b, sym_exit_keys); while (1) { - key = ui_browser__run(&self->b); + key = ui_browser__run(&self->b, delay_secs); switch (key) { case -1: @@ -1061,7 +1057,6 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, void(*timer)(void *arg), void *arg, int delay_secs) { int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; - int delay_msecs = delay_secs * 1000; struct perf_evlist *evlist = menu->b.priv; struct perf_evsel *pos; const char *ev_name, *title = "Available samples"; @@ -1071,13 +1066,10 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, "ESC: exit, ENTER|->: Browse histograms") < 0) return -1; - if (timer != NULL) - newtFormSetTimer(menu->b.form, delay_msecs); - ui_browser__add_exit_keys(&menu->b, exit_keys); while (1) { - key = ui_browser__run(&menu->b); + key = ui_browser__run(&menu->b, delay_secs); switch (key) { case -1: diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index 8462bffe20bc..499db76bac2f 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/util/ui/browsers/map.c @@ -1,5 +1,6 @@ #include "../libslang.h" #include +#include #include #include #include @@ -112,7 +113,7 @@ static int map_browser__run(struct map_browser *self) ui_browser__add_exit_key(&self->b, '/'); while (1) { - key = ui_browser__run(&self->b); + key = ui_browser__run(&self->b, 0); if (verbose && key == '/') map_browser__search(self); diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h index ab6028d0c401..809975759080 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/util/ui/helpline.h @@ -1,6 +1,8 @@ #ifndef _PERF_UI_HELPLINE_H_ #define _PERF_UI_HELPLINE_H_ 1 +#include + void ui_helpline__init(void); void ui_helpline__pop(void); void ui_helpline__push(const char *msg); -- cgit v1.2.3 From ed7e5662ddff6a60bdae830ff65547c2eeed6f9a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Oct 2011 08:31:22 -0300 Subject: perf ui browser: Remove ui_browser__add_exit_keys Users (hist_browser, etc) should just handle all keys, discarding the ones they don't handle. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-fjouann12v2k58t6vdd2wawb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browser.c | 18 ------------------ tools/perf/util/ui/browser.h | 2 -- tools/perf/util/ui/browsers/annotate.c | 12 ++++-------- tools/perf/util/ui/browsers/hists.c | 28 ++++++++-------------------- tools/perf/util/ui/browsers/map.c | 3 --- 5 files changed, 12 insertions(+), 51 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 05a0f61312d8..2923c493fb6a 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -142,20 +142,6 @@ void ui_browser__reset_index(struct ui_browser *self) self->seek(self, 0, SEEK_SET); } -void ui_browser__add_exit_key(struct ui_browser *browser __used, int key __used) -{ -} - -void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) -{ - int i = 0; - - while (keys[i] && i < 64) { - ui_browser__add_exit_key(self, keys[i]); - ++i; - } -} - void __ui_browser__show_title(struct ui_browser *browser, const char *title) { SLsmg_gotorc(0, 0); @@ -175,16 +161,12 @@ int ui_browser__show(struct ui_browser *self, const char *title, { int err; va_list ap; - int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP, - NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ', - NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 }; ui_browser__refresh_dimensions(self); pthread_mutex_lock(&ui__lock); __ui_browser__show_title(self, title); - ui_browser__add_exit_keys(self, keys); self->title = title; free(self->helpline); self->helpline = NULL; diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 37d56bfe8fe3..7dd9d6107d12 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -32,8 +32,6 @@ void ui_browser__refresh_dimensions(struct ui_browser *self); void ui_browser__reset_index(struct ui_browser *self); void ui_browser__gotorc(struct ui_browser *self, int y, int x); -void ui_browser__add_exit_key(struct ui_browser *self, int key); -void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); void __ui_browser__show_title(struct ui_browser *browser, const char *title); void ui_browser__show_title(struct ui_browser *browser, const char *title); int ui_browser__show(struct ui_browser *self, const char *title, diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 1967fbf73998..cbefb4fc99c4 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -175,12 +175,6 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, struct rb_node *nd = NULL; struct map_symbol *ms = self->b.priv; struct symbol *sym = ms->sym; - /* - * RIGHT To allow builtin-annotate to cycle thru multiple symbols by - * examining the exit key for this function. - */ - int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, - NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 }; int key; if (ui_browser__show(&self->b, sym->name, @@ -188,7 +182,6 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, "cycle hottest lines, H: Hottest, -> Line action") < 0) return -1; - ui_browser__add_exit_keys(&self->b, exit_keys); annotate_browser__calc_percent(self, evidx); if (self->curr_hot) @@ -292,8 +285,11 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, timer, arg, delay_secs); } break; - default: + case 'q': + case CTRL('c'): goto out; + default: + continue; } if (nd != NULL) diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 603d6ee5a0d7..662b7217a031 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -302,9 +302,6 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, { int key; char title[160]; - int sym_exit_keys[] = { 'a', 'h', 'C', 'd', 'E', 't', 0, }; - int exit_keys[] = { '?', 'h', 'D', NEWT_KEY_LEFT, NEWT_KEY_RIGHT, - NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, }; self->b.entries = &self->hists->entries; self->b.nr_entries = self->hists->nr_entries; @@ -317,10 +314,6 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, "Press '?' for help on key bindings") < 0) return -1; - ui_browser__add_exit_keys(&self->b, exit_keys); - if (self->has_symbols) - ui_browser__add_exit_keys(&self->b, sym_exit_keys); - while (1) { key = ui_browser__run(&self->b, delay_secs); @@ -921,8 +914,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, !ui__dialog_yesno("Do you really want to exit?")) continue; /* Fall thru */ - default: + case 'q': + case CTRL('c'): goto out_free_stack; + default: + continue; } if (!browser->has_symbols) @@ -1056,7 +1052,6 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, int nr_events, const char *help, void(*timer)(void *arg), void *arg, int delay_secs) { - int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; struct perf_evlist *evlist = menu->b.priv; struct perf_evsel *pos; const char *ev_name, *title = "Available samples"; @@ -1066,8 +1061,6 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, "ESC: exit, ENTER|->: Browse histograms") < 0) return -1; - ui_browser__add_exit_keys(&menu->b, exit_keys); - while (1) { key = ui_browser__run(&menu->b, delay_secs); @@ -1091,15 +1084,6 @@ browse_hists: break; case NEWT_KEY_LEFT: continue; - case NEWT_KEY_ESCAPE: - if (!ui__dialog_yesno("Do you really want to exit?")) - continue; - /* Fall thru */ - default: - goto out; - } - - switch (key) { case NEWT_KEY_TAB: if (pos->node.next == &evlist->entries) pos = list_entry(evlist->entries.next, struct perf_evsel, node); @@ -1114,6 +1098,10 @@ browse_hists: pos = list_entry(pos->node.prev, struct perf_evsel, node); perf_evlist__set_selected(evlist, pos); goto browse_hists; + case NEWT_KEY_ESCAPE: + if (!ui__dialog_yesno("Do you really want to exit?")) + continue; + /* Fall thru */ case 'q': case CTRL('c'): goto out; diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index 499db76bac2f..6905bcc8be2d 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/util/ui/browsers/map.c @@ -109,9 +109,6 @@ static int map_browser__run(struct map_browser *self) verbose ? "" : "restart with -v to use") < 0) return -1; - if (verbose) - ui_browser__add_exit_key(&self->b, '/'); - while (1) { key = ui_browser__run(&self->b, 0); -- cgit v1.2.3 From 18eaf0b8e60a2fa54667b2192197970174f1c061 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Oct 2011 12:22:28 -0300 Subject: perf hists browser: Fix handling of TAB/UNTAB for multiple events When using multiple events the 'top' and 'report' tools will first present the user with a menu to choose the event to browse. After that the user can either press <- to go back to the menu and choose another event or instead press TAB to go the next event without having to go back to the menu or shift-TAB (UNTAB) to go the previous event, useful to quickly visually see if multiple events are correlated. The handling of each hists browser return was broken by the ed7e566, that combined both switches, the first that was for choosing the event and the second that was for checking if switching to the next event without passing thru the events menu. Repeat with me: Don't be clever like that. Fix it by moving the switch to right after the call to the hists browser, making abundantly clear that the two switches are unrelated. This also fixes a compiler warning about the 'pos' variable being possibly used unitialized. Reported-by: Ingo Molnar [ committer note: the line above is for the compiler warning ] Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ujxkbvj9vy8w6xe2op5m51tb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 48 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 662b7217a031..4a3a7c96b9b6 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1074,30 +1074,44 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, if (!menu->selection) continue; pos = menu->selection; - perf_evlist__set_selected(evlist, pos); browse_hists: + perf_evlist__set_selected(evlist, pos); + /* + * Give the calling tool a chance to populate the non + * default evsel resorted hists tree. + */ + if (timer) + timer(arg); ev_name = event_name(pos); key = perf_evsel__hists_browse(pos, nr_events, help, ev_name, true, timer, arg, delay_secs); ui_browser__show_title(&menu->b, title); - break; + switch (key) { + case NEWT_KEY_TAB: + if (pos->node.next == &evlist->entries) + pos = list_entry(evlist->entries.next, struct perf_evsel, node); + else + pos = list_entry(pos->node.next, struct perf_evsel, node); + goto browse_hists; + case NEWT_KEY_UNTAB: + if (pos->node.prev == &evlist->entries) + pos = list_entry(evlist->entries.prev, struct perf_evsel, node); + else + pos = list_entry(pos->node.prev, struct perf_evsel, node); + goto browse_hists; + case NEWT_KEY_ESCAPE: + if (!ui__dialog_yesno("Do you really want to exit?")) + continue; + /* Fall thru */ + case 'q': + case CTRL('c'): + goto out; + default: + continue; + } case NEWT_KEY_LEFT: continue; - case NEWT_KEY_TAB: - if (pos->node.next == &evlist->entries) - pos = list_entry(evlist->entries.next, struct perf_evsel, node); - else - pos = list_entry(pos->node.next, struct perf_evsel, node); - perf_evlist__set_selected(evlist, pos); - goto browse_hists; - case NEWT_KEY_UNTAB: - if (pos->node.prev == &evlist->entries) - pos = list_entry(evlist->entries.prev, struct perf_evsel, node); - else - pos = list_entry(pos->node.prev, struct perf_evsel, node); - perf_evlist__set_selected(evlist, pos); - goto browse_hists; case NEWT_KEY_ESCAPE: if (!ui__dialog_yesno("Do you really want to exit?")) continue; @@ -1106,7 +1120,7 @@ browse_hists: case CTRL('c'): goto out; default: - break; + continue; } } -- cgit v1.2.3 From 437cfe7a37df07e2201036fb0903cadae6b08e74 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Oct 2011 09:31:53 -0300 Subject: perf hists browser: Invalidate ui_browser->top after timer calls With underlying dynamic data structures we need to invalidate pointers to them after a timer, as that entry may have vanished (decayed in top, for instance). I forgot about browser_ui->top. Fix it by resetting it to null after a timer. The seek operation from SEEK_SET will then set it to a valid entry because it starts from rb_first(&hists->entries). Reported-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2ssjm0ouh9tsz4dwkcu7c40n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browser.c | 1 + tools/perf/util/ui/browsers/hists.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 2923c493fb6a..078ceaf5f8c1 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -249,6 +249,7 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) browser->top_idx += offset; } + browser->top = NULL; browser->seek(browser, browser->top_idx, SEEK_SET); } diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 4a3a7c96b9b6..b144b108029a 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -600,14 +600,23 @@ static int hist_browser__show_entry(struct hist_browser *self, return printed; } +static void ui_browser__hists_init_top(struct ui_browser *browser) +{ + if (browser->top == NULL) { + struct hist_browser *hb; + + hb = container_of(browser, struct hist_browser, b); + browser->top = rb_first(&hb->hists->entries); + } +} + static unsigned int hist_browser__refresh(struct ui_browser *self) { unsigned row = 0; struct rb_node *nd; struct hist_browser *hb = container_of(self, struct hist_browser, b); - if (self->top == NULL) - self->top = rb_first(&hb->hists->entries); + ui_browser__hists_init_top(self); for (nd = self->top; nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); @@ -659,6 +668,8 @@ static void ui_browser__hists_seek(struct ui_browser *self, if (self->nr_entries == 0) return; + ui_browser__hists_init_top(self); + switch (whence) { case SEEK_SET: nd = hists__filter_entries(rb_first(self->entries)); -- cgit v1.2.3 From 2d5646c0d58697c63e1fe6f227165637ca04a6c4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Oct 2011 13:02:52 -0200 Subject: perf hists browser: Add missing hotkeys to the help window The navigation keys were missing (UP, DOWN arrows, etc). Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3pnln0bws5v0yoqwd3f020nx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index b144b108029a..873b852e914e 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -886,17 +886,20 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, case NEWT_KEY_F1: case 'h': case '?': - ui__help_window("h/?/F1 Show this window\n" - "TAB/UNTAB Switch events\n" - "q/CTRL+C Exit browser\n\n" + ui__help_window("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"); + "-> 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"); continue; case NEWT_KEY_ENTER: case NEWT_KEY_RIGHT: -- cgit v1.2.3 From c172f7422c03463a7177e268ffe625c41c42c179 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Oct 2011 14:31:35 -0200 Subject: perf ui browser: Allow initial use without navigation UI elements The selection and scroll bar are really needed only when the user starts navigating, before that it just provide distractions. This also brings the initial screen to look more like the stdio UI, which more people are used to. The new code is flexible enough that menu like browsers can opt out and start with those UI elements. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jfgok30kkerpfw8wtcltgy6z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browser.c | 28 +++++++++++++++++++++++----- tools/perf/util/ui/browser.h | 2 ++ tools/perf/util/ui/browsers/annotate.c | 6 ++++++ tools/perf/util/ui/browsers/hists.c | 20 ++++++++------------ 4 files changed, 39 insertions(+), 17 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index a54b926efe2b..dce16ee43645 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -14,9 +14,10 @@ int newtGetKey(void); -static int ui_browser__percent_color(double percent, bool current) +static int ui_browser__percent_color(struct ui_browser *browser, + double percent, bool current) { - if (current) + if (current && (!browser->use_navkeypressed || browser->navkeypressed)) return HE_COLORSET_SELECTED; if (percent >= MIN_RED) return HE_COLORSET_TOP; @@ -33,7 +34,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color) void ui_browser__set_percent_color(struct ui_browser *self, double percent, bool current) { - int color = ui_browser__percent_color(percent, current); + int color = ui_browser__percent_color(self, percent, current); ui_browser__set_color(self, color); } @@ -241,12 +242,18 @@ static void ui_browser__scrollbar_set(struct ui_browser *browser) static int __ui_browser__refresh(struct ui_browser *browser) { int row; + int width = browser->width; row = browser->refresh(browser); ui_browser__set_color(browser, HE_COLORSET_NORMAL); + + if (!browser->use_navkeypressed || browser->navkeypressed) + ui_browser__scrollbar_set(browser); + else + width += 1; + SLsmg_fill_region(browser->y + row, browser->x, - browser->height - row, browser->width, ' '); - ui_browser__scrollbar_set(browser); + browser->height - row, width, ' '); return 0; } @@ -326,6 +333,17 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) continue; } + if (self->use_navkeypressed && !self->navkeypressed) { + if (key == NEWT_KEY_DOWN || key == NEWT_KEY_UP || + key == NEWT_KEY_PGDN || key == NEWT_KEY_PGUP || + key == NEWT_KEY_HOME || key == NEWT_KEY_END || + key == ' ') { + self->navkeypressed = true; + continue; + } else + return key; + } + switch (key) { case NEWT_KEY_DOWN: if (self->index == self->nr_entries - 1) diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 351c006dd4b5..a2c707d33c5e 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -23,6 +23,8 @@ struct ui_browser { void (*seek)(struct ui_browser *self, off_t offset, int whence); bool (*filter)(struct ui_browser *self, void *entry); u32 nr_entries; + bool navkeypressed; + bool use_navkeypressed; }; void ui_browser__set_color(struct ui_browser *self, int color); diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index eb2712ecb601..a2c351cf23eb 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -69,6 +69,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro SLsmg_write_char(':'); slsmg_write_nstring(" ", 8); + + /* The scroll bar isn't being used */ + if (!self->navkeypressed) + width += 1; + if (!*ol->line) slsmg_write_nstring(" ", width - 18); else @@ -386,6 +391,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, .write = annotate_browser__write, .filter = objdump_line__filter, .priv = &ms, + .use_navkeypressed = true, }, }; int ret; diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 873b852e914e..2d390b9cb63e 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -547,7 +547,7 @@ static int hist_browser__show_entry(struct hist_browser *self, char s[256]; double percent; int printed = 0; - int color, width = self->b.width; + int width = self->b.width; char folded_sign = ' '; bool current_entry = ui_browser__is_current_entry(&self->b, row); off_t row_offset = entry->row_offset; @@ -567,22 +567,17 @@ static int hist_browser__show_entry(struct hist_browser *self, 0, false, self->hists->stats.total_period); percent = (entry->period * 100.0) / self->hists->stats.total_period; - color = HE_COLORSET_SELECTED; - if (!current_entry) { - if (percent >= MIN_RED) - color = HE_COLORSET_TOP; - else if (percent >= MIN_GREEN) - color = HE_COLORSET_MEDIUM; - else - color = HE_COLORSET_NORMAL; - } - - ui_browser__set_color(&self->b, color); + ui_browser__set_percent_color(&self->b, percent, current_entry); ui_browser__gotorc(&self->b, row, 0); if (symbol_conf.use_callchain) { slsmg_printf("%c ", folded_sign); width -= 2; } + + /* The scroll bar isn't being used */ + if (!self->b.navkeypressed) + width += 1; + slsmg_write_nstring(s, width); ++row; ++printed; @@ -787,6 +782,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists) self->hists = hists; self->b.refresh = hist_browser__refresh; self->b.seek = ui_browser__hists_seek; + self->b.use_navkeypressed = true, self->has_symbols = sort_sym.list.next != NULL; } -- cgit v1.2.3 From f1cf602c16e9a93fd16705621f3430ec7ffe2c44 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Oct 2011 14:37:34 -0200 Subject: perf hists: Don't format the percentage on hist_entry__snprintf We can't have color correctly set there because in libslang (and in a future GUI) the colors must be set on a separate function call, so move that part to a separate function and make the stdio fprintf function call it. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jpgy42438ce9tgbqppm397lq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 29 ++++++++++++++++++++--------- tools/perf/util/hist.h | 4 +--- tools/perf/util/ui/browsers/hists.c | 7 ++++--- 3 files changed, 25 insertions(+), 15 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 48da373afa3d..8d15e9f72f00 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -707,12 +707,11 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) } } -int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, - struct hists *hists, struct hists *pair_hists, - bool show_displacement, long displacement, - bool color, u64 session_total) +static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, + size_t size, struct hists *pair_hists, + bool show_displacement, long displacement, + bool color, u64 session_total) { - struct sort_entry *se; u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; u64 nr_events; const char *sep = symbol_conf.field_sep; @@ -818,12 +817,22 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, } } + return ret; +} + +int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, + struct hists *hists) +{ + const char *sep = symbol_conf.field_sep; + struct sort_entry *se; + int ret = 0; + list_for_each_entry(se, &hist_entry__sort_list, list) { if (se->elide) continue; ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); - ret += se->se_snprintf(self, s + ret, size - ret, + ret += se->se_snprintf(he, s + ret, size - ret, hists__col_len(hists, se->se_width_idx)); } @@ -835,13 +844,15 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, long displacement, FILE *fp, u64 session_total) { char bf[512]; + int ret; if (size == 0 || size > sizeof(bf)) size = sizeof(bf); - hist_entry__snprintf(he, bf, size, hists, pair_hists, - show_displacement, displacement, - true, session_total); + ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists, + show_displacement, displacement, + true, session_total); + hist_entry__snprintf(he, bf + ret, size - ret, hists); return fprintf(fp, "%s\n", bf); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ea96c1cbb850..f338cb025671 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -68,9 +68,7 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, struct hists *pair_hists, bool show_displacement, long displacement, FILE *fp, u64 session_total); int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, - struct hists *hists, struct hists *pair_hists, - bool show_displacement, long displacement, - bool color, u64 total); + struct hists *hists); void hist_entry__free(struct hist_entry *); void hists__output_resort(struct hists *self); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 2d390b9cb63e..0eced19e3bdb 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -547,7 +547,7 @@ static int hist_browser__show_entry(struct hist_browser *self, char s[256]; double percent; int printed = 0; - int width = self->b.width; + int width = self->b.width - 6; /* The percentage */ char folded_sign = ' '; bool current_entry = ui_browser__is_current_entry(&self->b, row); off_t row_offset = entry->row_offset; @@ -563,8 +563,7 @@ static int hist_browser__show_entry(struct hist_browser *self, } if (row_offset == 0) { - hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, - 0, false, self->hists->stats.total_period); + hist_entry__snprintf(entry, s, sizeof(s), self->hists); percent = (entry->period * 100.0) / self->hists->stats.total_period; ui_browser__set_percent_color(&self->b, percent, current_entry); @@ -574,6 +573,8 @@ static int hist_browser__show_entry(struct hist_browser *self, width -= 2; } + slsmg_printf(" %5.2f%%", percent); + /* The scroll bar isn't being used */ if (!self->b.navkeypressed) width += 1; -- cgit v1.2.3 From 33f62b3fc4edd46d80c4420b81dfcb267c8bdb5e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Oct 2011 15:54:24 -0200 Subject: perf top tui: Give color hints just on the percentage, like on --stdio And like it was in the old top. Another change so that the familiarity with the old visual is maintained. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ypmyx9p0ah4byqaygrnb09x8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 0eced19e3bdb..936e641e9f86 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -579,6 +579,9 @@ static int hist_browser__show_entry(struct hist_browser *self, if (!self->b.navkeypressed) width += 1; + if (!current_entry || !self->b.navkeypressed) + ui_browser__set_color(&self->b, HE_COLORSET_NORMAL); + slsmg_write_nstring(s, width); ++row; ++printed; -- cgit v1.2.3 From d7b76f0935d294e9abaac1577cdc2137eff15a49 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Oct 2011 19:07:34 -0200 Subject: perf hists: Move the dso and thread filters from hist_browser Since with dynamic addition of new hist entries we need to apply those filters as we merge new batches of hist_entry instances, for instance in perf top. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-zjhhf8kh9w1buty9p10od6rz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 10 ++++---- tools/perf/util/hist.h | 9 +++++-- tools/perf/util/ui/browsers/hists.c | 48 +++++++++++++++++-------------------- 3 files changed, 35 insertions(+), 32 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 8d15e9f72f00..fdff2a8288b4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1087,7 +1087,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h hists__calc_col_len(hists, h); } -void hists__filter_by_dso(struct hists *hists, const struct dso *dso) +void hists__filter_by_dso(struct hists *hists) { struct rb_node *nd; @@ -1101,7 +1101,8 @@ void hists__filter_by_dso(struct hists *hists, const struct dso *dso) if (symbol_conf.exclude_other && !h->parent) continue; - if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { + if (hists->dso_filter != NULL && + (h->ms.map == NULL || h->ms.map->dso != hists->dso_filter)) { h->filtered |= (1 << HIST_FILTER__DSO); continue; } @@ -1110,7 +1111,7 @@ void hists__filter_by_dso(struct hists *hists, const struct dso *dso) } } -void hists__filter_by_thread(struct hists *hists, const struct thread *thread) +void hists__filter_by_thread(struct hists *hists) { struct rb_node *nd; @@ -1121,7 +1122,8 @@ void hists__filter_by_thread(struct hists *hists, const struct thread *thread) for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - if (thread != NULL && h->thread != thread) { + if (hists->thread_filter != NULL && + h->thread != hists->thread_filter) { h->filtered |= (1 << HIST_FILTER__THREAD); continue; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f338cb025671..575bcbc41355 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -43,12 +43,17 @@ enum hist_column { HISTC_NR_COLS, /* Last entry */ }; +struct thread; +struct dso; + struct hists { struct rb_root entries_in_array[2]; struct rb_root *entries_in; struct rb_root entries; struct rb_root entries_collapsed; u64 nr_entries; + const struct thread *thread_filter; + const struct dso *dso_filter; pthread_mutex_t lock; struct events_stats stats; u64 event_stream; @@ -91,8 +96,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); int hist_entry__annotate(struct hist_entry *self, size_t privsize); -void hists__filter_by_dso(struct hists *self, const struct dso *dso); -void hists__filter_by_thread(struct hists *self, const struct thread *thread); +void hists__filter_by_dso(struct hists *hists); +void hists__filter_by_thread(struct hists *hists); u16 hists__col_len(struct hists *self, enum hist_column col); void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 936e641e9f86..94e1ab0badb1 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -24,14 +24,11 @@ struct hist_browser { struct hists *hists; struct hist_entry *he_selection; struct map_symbol *selection; - const struct thread *thread_filter; - const struct dso *dso_filter; bool has_symbols; }; static int hists__browser_title(struct hists *self, char *bf, size_t size, - const char *ev_name, const struct dso *dso, - const struct thread *thread); + const char *ev_name); static void hist_browser__refresh_dimensions(struct hist_browser *self) { @@ -307,8 +304,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, self->b.nr_entries = self->hists->nr_entries; hist_browser__refresh_dimensions(self); - hists__browser_title(self->hists, title, sizeof(title), ev_name, - self->dso_filter, self->thread_filter); + hists__browser_title(self->hists, title, sizeof(title), ev_name); if (ui_browser__show(&self->b, title, "Press '?' for help on key bindings") < 0) @@ -323,8 +319,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, timer(arg); ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); hists__browser_title(self->hists, title, sizeof(title), - ev_name, self->dso_filter, - self->thread_filter); + ev_name); ui_browser__show_title(&self->b, title); continue; case 'D': { /* Debug */ @@ -809,11 +804,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) } static int hists__browser_title(struct hists *self, char *bf, size_t size, - const char *ev_name, const struct dso *dso, - const struct thread *thread) + const char *ev_name) { char unit; int printed; + const struct dso *dso = self->dso_filter; + const struct thread *thread = self->thread_filter; unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; nr_events = convert_unit(nr_events, &unit); @@ -917,9 +913,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; } top = pstack__pop(fstack); - if (top == &browser->dso_filter) + if (top == &browser->hists->dso_filter) goto zoom_out_dso; - if (top == &browser->thread_filter) + if (top == &browser->hists->thread_filter) goto zoom_out_thread; continue; } @@ -947,14 +943,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (thread != NULL && asprintf(&options[nr_options], "Zoom %s %s(%d) thread", - (browser->thread_filter ? "out of" : "into"), + (browser->hists->thread_filter ? "out of" : "into"), (thread->comm_set ? thread->comm : ""), thread->pid) > 0) zoom_thread = nr_options++; if (dso != NULL && asprintf(&options[nr_options], "Zoom %s %s DSO", - (browser->dso_filter ? "out of" : "into"), + (browser->hists->dso_filter ? "out of" : "into"), (dso->kernel ? "the Kernel" : dso->short_name)) > 0) zoom_dso = nr_options++; @@ -994,36 +990,36 @@ do_annotate: map__browse(browser->selection->map); else if (choice == zoom_dso) { zoom_dso: - if (browser->dso_filter) { - pstack__remove(fstack, &browser->dso_filter); + if (browser->hists->dso_filter) { + pstack__remove(fstack, &browser->hists->dso_filter); zoom_out_dso: ui_helpline__pop(); - browser->dso_filter = NULL; + browser->hists->dso_filter = NULL; } 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->dso_filter = dso; - pstack__push(fstack, &browser->dso_filter); + browser->hists->dso_filter = dso; + pstack__push(fstack, &browser->hists->dso_filter); } - hists__filter_by_dso(self, browser->dso_filter); + hists__filter_by_dso(self); hist_browser__reset(browser); } else if (choice == zoom_thread) { zoom_thread: - if (browser->thread_filter) { - pstack__remove(fstack, &browser->thread_filter); + if (browser->hists->thread_filter) { + pstack__remove(fstack, &browser->hists->thread_filter); zoom_out_thread: ui_helpline__pop(); - browser->thread_filter = NULL; + browser->hists->thread_filter = NULL; } else { ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", thread->comm_set ? thread->comm : "", thread->pid); - browser->thread_filter = thread; - pstack__push(fstack, &browser->thread_filter); + browser->hists->thread_filter = thread; + pstack__push(fstack, &browser->hists->thread_filter); } - hists__filter_by_thread(self, browser->thread_filter); + hists__filter_by_thread(self); hist_browser__reset(browser); } } -- cgit v1.2.3 From e4419b8edb6dead17cbc13a477b953399ee7571c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 19 Oct 2011 11:37:47 -0600 Subject: perf hists browser: Do not exit on tab key with single event TUI help states for multiple event sessions the TAB/UNTAB keys are used to switch events. For single event sessions (e.g., the default) the tab key currently causes the tui to exit. Change that to do nothing since there is not no second event to switch to. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1319045867-12728-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 94e1ab0badb1..d76287513525 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -864,6 +864,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, switch (key) { case NEWT_KEY_TAB: case NEWT_KEY_UNTAB: + if (nr_events == 1) + continue; /* * Exit the browser, let hists__browser_tree * go to the next or previous -- cgit v1.2.3 From 2cf9cebf0878e384630f6fd5e1abd830c0cd99b3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Oct 2011 14:37:59 -0200 Subject: perf hists browser: Honour symbol_conf.show_{nr_samples,total_period} We lost that when we move it outside hist_entry__snprintf, but better leave it untangled of 'perf diff' stuff (pair_hist, etc). Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-qlhb6ictf5twykog6x344s0b@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index d76287513525..9e23bce98827 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -577,6 +577,16 @@ static int hist_browser__show_entry(struct hist_browser *self, if (!current_entry || !self->b.navkeypressed) ui_browser__set_color(&self->b, HE_COLORSET_NORMAL); + if (symbol_conf.show_nr_samples) { + slsmg_printf(" %11u", entry->nr_events); + width -= 12; + } + + if (symbol_conf.show_total_period) { + slsmg_printf(" %12" PRIu64, entry->period); + width -= 13; + } + slsmg_write_nstring(s, width); ++row; ++printed; -- cgit v1.2.3 From cc02c921a01794f85ad53b396133f11d4ddd17ff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 Oct 2011 08:02:30 -0200 Subject: perf hists browser: Elide DSO column when it is set to just one DSO, ditto for threads And also no leed to show the [.] (level: k, . for userspace) when showing just one DSO. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-4h3f6ro5o7ebepjbssxf0dd3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 4 +++- tools/perf/util/ui/browsers/hists.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 1ee8f1e40f18..16da30d8d765 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -177,7 +177,9 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, BITS_PER_LONG / 4, self->ip, o); } - ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); + if (!sort_dso.elide) + ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); + if (self->ms.sym) ret += repsep_snprintf(bf + ret, size - ret, "%s", self->ms.sym->name); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 9e23bce98827..a06e7d936ec1 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1007,12 +1007,14 @@ zoom_dso: zoom_out_dso: ui_helpline__pop(); browser->hists->dso_filter = NULL; + sort_dso.elide = 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; pstack__push(fstack, &browser->hists->dso_filter); } hists__filter_by_dso(self); @@ -1024,11 +1026,13 @@ zoom_thread: zoom_out_thread: ui_helpline__pop(); browser->hists->thread_filter = NULL; + sort_thread.elide = false; } else { ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", thread->comm_set ? thread->comm : "", thread->pid); browser->hists->thread_filter = thread; + sort_thread.elide = true; pstack__push(fstack, &browser->hists->thread_filter); } hists__filter_by_thread(self); -- cgit v1.2.3 From cf9580036a830f9e95f32dbcedfc57ea1697f120 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 Oct 2011 16:59:15 -0200 Subject: perf ui browser: Use libslang to read keys Just another step in stopping the use of libnewt in perf. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-uy6s534uqxq8tenh6s3k8ocj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 8 ++-- tools/perf/util/hist.h | 9 ++-- tools/perf/util/ui/browser.c | 79 +++++++++++++++++++++++----------- tools/perf/util/ui/browsers/annotate.c | 19 ++++---- tools/perf/util/ui/browsers/hists.c | 33 +++++++------- tools/perf/util/ui/keysyms.h | 25 +++++++++++ tools/perf/util/ui/libslang.h | 2 + tools/perf/util/ui/setup.c | 13 ++++++ 9 files changed, 125 insertions(+), 64 deletions(-) create mode 100644 tools/perf/util/ui/keysyms.h (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 37fe93019bc6..b98e3075646b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -472,6 +472,7 @@ else LIB_H += util/ui/browser.h LIB_H += util/ui/browsers/map.h LIB_H += util/ui/helpline.h + LIB_H += util/ui/keysyms.h LIB_H += util/ui/libslang.h LIB_H += util/ui/progress.h LIB_H += util/ui/util.h diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3ea764a78053..46b4c24f338e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -118,7 +118,7 @@ static void hists__find_annotations(struct hists *self, int evidx, int nr_events) { struct rb_node *nd = rb_first(&self->entries), *next; - int key = KEY_RIGHT; + int key = K_RIGHT; while (nd) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); @@ -130,7 +130,7 @@ static void hists__find_annotations(struct hists *self, int evidx, notes = symbol__annotation(he->ms.sym); if (notes->src == NULL) { find_next: - if (key == KEY_LEFT) + if (key == K_LEFT) nd = rb_prev(nd); else nd = rb_next(nd); @@ -141,10 +141,10 @@ find_next: key = hist_entry__tui_annotate(he, evidx, nr_events, NULL, NULL, 0); switch (key) { - case KEY_RIGHT: + case K_RIGHT: next = rb_next(nd); break; - case KEY_LEFT: + case K_LEFT: next = rb_prev(nd); break; default: diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 575bcbc41355..ff93ddc91c5c 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -125,16 +125,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, { return 0; } -#define KEY_LEFT -1 -#define KEY_RIGHT -2 +#define K_LEFT -1 +#define K_RIGHT -2 #else -#include +#include "ui/keysyms.h" int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs); -#define KEY_LEFT NEWT_KEY_LEFT -#define KEY_RIGHT NEWT_KEY_RIGHT - int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, void(*timer)(void *arg), void *arg, int refresh); diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 06fc9ebd8d3f..5359f371d30a 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -11,10 +11,9 @@ #include #include "browser.h" #include "helpline.h" +#include "keysyms.h" #include "../color.h" -int newtGetKey(void); - static int ui_browser__percent_color(struct ui_browser *browser, double percent, bool current) { @@ -292,16 +291,55 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) browser->seek(browser, browser->top_idx, SEEK_SET); } +static int ui__getch(int delay_secs) +{ + struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; + fd_set read_set; + int err, key; + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + + if (delay_secs) { + timeout.tv_sec = delay_secs; + timeout.tv_usec = 0; + } + + err = select(1, &read_set, NULL, NULL, ptimeout); + + if (err == 0) + return K_TIMER; + + if (err == -1) { + if (errno == EINTR) + return K_RESIZE; + return K_ERROR; + } + + key = SLang_getkey(); + if (key != K_ESC) + return key; + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + timeout.tv_sec = 0; + timeout.tv_usec = 20; + err = select(1, &read_set, NULL, NULL, &timeout); + if (err == 0) + return K_ESC; + + SLang_ungetkey(key); + return SLkp_getkey(); +} + int ui_browser__run(struct ui_browser *self, int delay_secs) { int err, key; - struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; pthread__unblock_sigwinch(); while (1) { off_t offset; - fd_set read_set; pthread_mutex_lock(&ui__lock); err = __ui_browser__refresh(self); @@ -310,20 +348,9 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) if (err < 0) break; - FD_ZERO(&read_set); - FD_SET(0, &read_set); + key = ui__getch(delay_secs); - if (delay_secs) { - timeout.tv_sec = delay_secs; - timeout.tv_usec = 0; - } - - err = select(1, &read_set, NULL, NULL, ptimeout); - if (err > 0 && FD_ISSET(0, &read_set)) - key = newtGetKey(); - else if (err == 0) - break; - else { + if (key == K_RESIZE) { pthread_mutex_lock(&ui__lock); SLtt_get_screen_size(); SLsmg_reinit_smg(); @@ -335,9 +362,9 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) } if (self->use_navkeypressed && !self->navkeypressed) { - if (key == NEWT_KEY_DOWN || key == NEWT_KEY_UP || - key == NEWT_KEY_PGDN || key == NEWT_KEY_PGUP || - key == NEWT_KEY_HOME || key == NEWT_KEY_END || + if (key == K_DOWN || key == K_UP || + key == K_PGDN || key == K_PGUP || + key == K_HOME || key == K_END || key == ' ') { self->navkeypressed = true; continue; @@ -346,7 +373,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) } switch (key) { - case NEWT_KEY_DOWN: + case K_DOWN: if (self->index == self->nr_entries - 1) break; ++self->index; @@ -355,7 +382,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) self->seek(self, +1, SEEK_CUR); } break; - case NEWT_KEY_UP: + case K_UP: if (self->index == 0) break; --self->index; @@ -364,7 +391,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) self->seek(self, -1, SEEK_CUR); } break; - case NEWT_KEY_PGDN: + case K_PGDN: case ' ': if (self->top_idx + self->height > self->nr_entries - 1) break; @@ -376,7 +403,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) self->top_idx += offset; self->seek(self, +offset, SEEK_CUR); break; - case NEWT_KEY_PGUP: + case K_PGUP: if (self->top_idx == 0) break; @@ -389,10 +416,10 @@ int ui_browser__run(struct ui_browser *self, int delay_secs) self->top_idx -= offset; self->seek(self, -offset, SEEK_CUR); break; - case NEWT_KEY_HOME: + case K_HOME: ui_browser__reset_index(self); break; - case NEWT_KEY_END: + case K_END: offset = self->height - 1; if (offset >= self->nr_entries) offset = self->nr_entries - 1; diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 1a12d8fa8e99..4e0cb7fea7d9 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -6,6 +6,7 @@ #include "../../sort.h" #include "../../symbol.h" #include +#include static void ui__error_window(const char *fmt, ...) { @@ -265,18 +266,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, } switch (key) { - case -1: - /* - * FIXME we need to check if it was - * es.reason == NEWT_EXIT_TIMER - */ + case K_TIMER: if (timer != NULL) timer(arg); if (delay_secs != 0) symbol__annotate_decay_histogram(sym, evidx); continue; - case NEWT_KEY_TAB: + case K_TAB: if (nd != NULL) { nd = rb_prev(nd); if (nd == NULL) @@ -284,7 +281,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, } else nd = self->curr_hot; break; - case NEWT_KEY_UNTAB: + case K_UNTAB: if (nd != NULL) nd = rb_next(nd); if (nd == NULL) @@ -299,8 +296,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, if (annotate_browser__toggle_source(self)) ui_helpline__puts(help); continue; - case NEWT_KEY_ENTER: - case NEWT_KEY_RIGHT: + case K_ENTER: + case K_RIGHT: if (self->selection == NULL) { ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); continue; @@ -350,8 +347,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, timer, arg, delay_secs); } continue; - case NEWT_KEY_LEFT: - case NEWT_KEY_ESCAPE: + case K_LEFT: + case K_ESC: case 'q': case CTRL('c'): goto out; diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index a06e7d936ec1..af12e6f10792 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -344,7 +344,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, /* Expand the whole world. */ hist_browser__set_folding(self, true); break; - case NEWT_KEY_ENTER: + case K_ENTER: if (hist_browser__toggle_fold(self)) break; /* fall thru */ @@ -872,8 +872,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, } switch (key) { - case NEWT_KEY_TAB: - case NEWT_KEY_UNTAB: + case K_TAB: + case K_UNTAB: if (nr_events == 1) continue; /* @@ -891,7 +891,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, goto zoom_dso; case 't': goto zoom_thread; - case NEWT_KEY_F1: + case K_F1: case 'h': case '?': ui__help_window("h/?/F1 Show this window\n" @@ -909,11 +909,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "d Zoom into current DSO\n" "t Zoom into current Thread\n"); continue; - case NEWT_KEY_ENTER: - case NEWT_KEY_RIGHT: + case K_ENTER: + case K_RIGHT: /* menu */ break; - case NEWT_KEY_LEFT: { + case K_LEFT: { const void *top; if (pstack__empty(fstack)) { @@ -931,7 +931,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, goto zoom_out_thread; continue; } - case NEWT_KEY_ESCAPE: + case K_ESC: if (!left_exits && !ui__dialog_yesno("Do you really want to exit?")) continue; @@ -1091,12 +1091,11 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, key = ui_browser__run(&menu->b, delay_secs); switch (key) { - case -1: - /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ + case K_TIMER: timer(arg); continue; - case NEWT_KEY_RIGHT: - case NEWT_KEY_ENTER: + case K_RIGHT: + case K_ENTER: if (!menu->selection) continue; pos = menu->selection; @@ -1114,19 +1113,19 @@ browse_hists: arg, delay_secs); ui_browser__show_title(&menu->b, title); switch (key) { - case NEWT_KEY_TAB: + case K_TAB: if (pos->node.next == &evlist->entries) pos = list_entry(evlist->entries.next, struct perf_evsel, node); else pos = list_entry(pos->node.next, struct perf_evsel, node); goto browse_hists; - case NEWT_KEY_UNTAB: + case K_UNTAB: if (pos->node.prev == &evlist->entries) pos = list_entry(evlist->entries.prev, struct perf_evsel, node); else pos = list_entry(pos->node.prev, struct perf_evsel, node); goto browse_hists; - case NEWT_KEY_ESCAPE: + case K_ESC: if (!ui__dialog_yesno("Do you really want to exit?")) continue; /* Fall thru */ @@ -1136,9 +1135,9 @@ browse_hists: default: continue; } - case NEWT_KEY_LEFT: + case K_LEFT: continue; - case NEWT_KEY_ESCAPE: + case K_ESC: if (!ui__dialog_yesno("Do you really want to exit?")) continue; /* Fall thru */ diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h new file mode 100644 index 000000000000..3458b1985761 --- /dev/null +++ b/tools/perf/util/ui/keysyms.h @@ -0,0 +1,25 @@ +#ifndef _PERF_KEYSYMS_H_ +#define _PERF_KEYSYMS_H_ 1 + +#include "libslang.h" + +#define K_DOWN SL_KEY_DOWN +#define K_END SL_KEY_END +#define K_ENTER '\r' +#define K_ESC 033 +#define K_F1 SL_KEY_F(1) +#define K_HOME SL_KEY_HOME +#define K_LEFT SL_KEY_LEFT +#define K_PGDN SL_KEY_NPAGE +#define K_PGUP SL_KEY_PPAGE +#define K_RIGHT SL_KEY_RIGHT +#define K_TAB '\t' +#define K_UNTAB SL_KEY_UNTAB +#define K_UP SL_KEY_UP + +/* Not really keys */ +#define K_TIMER -1 +#define K_ERROR -2 +#define K_RESIZE -3 + +#endif /* _PERF_KEYSYMS_H_ */ diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h index 2b63e1c9b181..4d54b6450f5b 100644 --- a/tools/perf/util/ui/libslang.h +++ b/tools/perf/util/ui/libslang.h @@ -24,4 +24,6 @@ #define sltt_set_color SLtt_set_color #endif +#define SL_KEY_UNTAB 0x1000 + #endif /* _PERF_UI_SLANG_H_ */ diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c index 5111f1ae0447..1e6ba06980c4 100644 --- a/tools/perf/util/ui/setup.c +++ b/tools/perf/util/ui/setup.c @@ -18,6 +18,18 @@ static void newt_suspend(void *d __used) newtResume(); } +static int ui__init(void) +{ + int err = SLkp_init(); + + if (err < 0) + goto out; + + SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); +out: + return err; +} + static void ui__exit(void) { SLtt_set_cursor_visibility(1); @@ -44,6 +56,7 @@ void setup_browser(bool fallback_to_pager) use_browser = 1; newtInit(); + ui__init(); newtSetSuspendCallback(newt_suspend, NULL); ui_helpline__init(); ui_browser__init(); -- cgit v1.2.3 From a6e51f9fa9124ad6657e6f1c8df2b1033922e9d7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 21 Oct 2011 10:58:24 -0200 Subject: perf hists browser: Refuse 'a' hotkey on non symbolic views We don't allocate the histogram data structures for --sort lists without "sym", so, just like was done for the menu, don't try to annotate when 'a' is pressed, just warn the user about it. Reported-by: David Ahern Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-27mjg02s2mbw8lfxqv7jpzec@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index af12e6f10792..4663dcb2a19b 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -882,6 +882,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, */ goto out_free_stack; case 'a': + if (!browser->has_symbols) { + ui__warning( + "Annotation is only available for symbolic views, " + "include \"sym\" in --sort to use it."); + continue; + } + if (browser->selection == NULL || browser->selection->sym == NULL || browser->selection->map->dso->annotate_warned) -- cgit v1.2.3 From 13d8f96c6c98532567b7620210a41d57dbc2039f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 26 Oct 2011 08:05:34 -0200 Subject: perf hists browser: Use K_TIMER In the switch case entry for the timer routine. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ypw3i9kmxoq28skx7jy914it@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/hists.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 4663dcb2a19b..44210d471719 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -314,8 +314,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, key = ui_browser__run(&self->b, delay_secs); switch (key) { - case -1: - /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ + case K_TIMER: timer(arg); ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); hists__browser_title(self->hists, title, sizeof(title), @@ -914,7 +913,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "C Collapse all callchains\n" "E Expand all callchains\n" "d Zoom into current DSO\n" - "t Zoom into current Thread\n"); + "t Zoom into current Thread"); continue; case K_ENTER: case K_RIGHT: -- cgit v1.2.3 From 4610e4137b5fb93042a248928a2c0049ef7d4190 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 26 Oct 2011 12:04:37 -0200 Subject: perf ui browser: Handle K_RESIZE in dialog windows Just provide wrappers for things like ui__warning, ui__dialog_yesno and if they return K_RESIZE, refresh dimensions, redraw the entries, etc. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3ih7hyk9weryxaxb501sfq4u@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/debug.c | 7 ++++--- tools/perf/util/debug.h | 6 +++--- tools/perf/util/ui/browser.c | 40 +++++++++++++++++++++++++++++++++++++ tools/perf/util/ui/browser.h | 5 +++++ tools/perf/util/ui/browsers/hists.c | 22 +++++++++++++------- tools/perf/util/ui/helpline.c | 6 ++++++ tools/perf/util/ui/helpline.h | 2 ++ tools/perf/util/ui/util.c | 27 +++++++++++++++---------- tools/perf/util/ui/util.h | 5 +++-- 9 files changed, 94 insertions(+), 26 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 55634038af6b..26817daa2961 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...) } #ifdef NO_NEWT_SUPPORT -void ui__warning(const char *format, ...) +int ui__warning(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); + return 0; } #endif -void ui__error_paranoid(void) +int ui__error_paranoid(void) { - ui__error("Permission error - are you root?\n" + return ui__error("Permission error - are you root?\n" "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" " -1 - Not paranoid at all\n" " 0 - Disallow raw tracepoint access for unpriv\n" diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 16cc75227d2b..f2ce88d04f54 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -27,10 +27,10 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used, extern char ui_helpline__last_msg[]; int ui_helpline__show_help(const char *format, va_list ap); #include "ui/progress.h" -void ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); +int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); #endif -void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); -void ui__error_paranoid(void); +int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); +int ui__error_paranoid(void); #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 8607efa13564..d2051be04f12 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -169,6 +169,46 @@ void ui_browser__refresh_dimensions(struct ui_browser *self) self->x = 0; } +void ui_browser__handle_resize(struct ui_browser *browser) +{ + ui__refresh_dimensions(false); + ui_browser__show(browser, browser->title, ui_helpline__current); + ui_browser__refresh(browser); +} + +int ui_browser__warning(struct ui_browser *browser, const char *format, ...) +{ + va_list args; + int key; + + va_start(args, format); + while ((key = __ui__warning("Warning!", format, args)) == K_RESIZE) + ui_browser__handle_resize(browser); + va_end(args); + + return key; +} + +int ui_browser__help_window(struct ui_browser *browser, const char *text) +{ + int key; + + while ((key = ui__help_window(text)) == K_RESIZE) + ui_browser__handle_resize(browser); + + return key; +} + +bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text) +{ + int key; + + while ((key = ui__dialog_yesno(text)) == K_RESIZE) + ui_browser__handle_resize(browser); + + return key == K_ENTER || toupper(key) == 'Y'; +} + void ui_browser__reset_index(struct ui_browser *self) { self->index = self->top_idx = 0; diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 81a8d2afaa9b..fb1c59883e6a 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -43,6 +43,11 @@ void ui_browser__hide(struct ui_browser *self); int ui_browser__refresh(struct ui_browser *self); int ui_browser__run(struct ui_browser *browser, int delay_secs); void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); +void ui_browser__handle_resize(struct ui_browser *browser); + +int ui_browser__warning(struct ui_browser *browser, const char *format, ...); +int ui_browser__help_window(struct ui_browser *browser, const char *text); +bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); unsigned int ui_browser__argv_refresh(struct ui_browser *browser); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 44210d471719..b8733c0770cd 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -17,6 +17,7 @@ #include "../browser.h" #include "../helpline.h" #include "../util.h" +#include "../ui.h" #include "map.h" struct hist_browser { @@ -882,7 +883,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, goto out_free_stack; case 'a': if (!browser->has_symbols) { - ui__warning( + ui_browser__warning(&browser->b, "Annotation is only available for symbolic views, " "include \"sym\" in --sort to use it."); continue; @@ -900,7 +901,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, case K_F1: case 'h': case '?': - ui__help_window("h/?/F1 Show this window\n" + 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" @@ -939,7 +941,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, } case K_ESC: if (!left_exits && - !ui__dialog_yesno("Do you really want to exit?")) + !ui_browser__dialog_yesno(&browser->b, + "Do you really want to exit?")) continue; /* Fall thru */ case 'q': @@ -992,6 +995,7 @@ add_exit_option: if (choice == annotate) { struct hist_entry *he; + int err; do_annotate: he = hist_browser__selected_entry(browser); if (he == NULL) @@ -1000,10 +1004,12 @@ do_annotate: * Don't let this be freed, say, by hists__decay_entry. */ he->used = true; - hist_entry__tui_annotate(he, evsel->idx, nr_events, - timer, arg, delay_secs); + err = hist_entry__tui_annotate(he, evsel->idx, nr_events, + timer, arg, delay_secs); he->used = false; ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); + if (err) + ui_browser__handle_resize(&browser->b); } else if (choice == browse_map) map__browse(browser->selection->map); else if (choice == zoom_dso) { @@ -1132,7 +1138,8 @@ browse_hists: pos = list_entry(pos->node.prev, struct perf_evsel, node); goto browse_hists; case K_ESC: - if (!ui__dialog_yesno("Do you really want to exit?")) + if (!ui_browser__dialog_yesno(&menu->b, + "Do you really want to exit?")) continue; /* Fall thru */ case 'q': @@ -1144,7 +1151,8 @@ browse_hists: case K_LEFT: continue; case K_ESC: - if (!ui__dialog_yesno("Do you really want to exit?")) + if (!ui_browser__dialog_yesno(&menu->b, + "Do you really want to exit?")) continue; /* Fall thru */ case 'q': diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index 600243d766c0..6ef3c5691762 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c @@ -1,6 +1,7 @@ #define _GNU_SOURCE #include #include +#include #include "../debug.h" #include "helpline.h" @@ -11,12 +12,17 @@ void ui_helpline__pop(void) { } +char ui_helpline__current[512]; + void ui_helpline__push(const char *msg) { + const size_t sz = sizeof(ui_helpline__current); + SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); SLsmg_set_color(0); SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols); SLsmg_refresh(); + strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; } void ui_helpline__vpush(const char *fmt, va_list ap) diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h index fdcbc0270acd..7bab6b34e35e 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/util/ui/helpline.h @@ -11,4 +11,6 @@ void ui_helpline__vpush(const char *fmt, va_list ap); void ui_helpline__fpush(const char *fmt, ...); void ui_helpline__puts(const char *msg); +extern char ui_helpline__current[]; + #endif /* _PERF_UI_HELPLINE_H_ */ diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index ef9b79332fe8..45daa7c41dad 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c @@ -121,43 +121,48 @@ int ui__help_window(const char *text) return ui__question_window("Help", text, "Press any key...", 0); } -bool ui__dialog_yesno(const char *msg) +int ui__dialog_yesno(const char *msg) { - int answer = ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); - - return answer == K_ENTER; + return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); } -static void __ui__warning(const char *title, const char *format, va_list args) +int __ui__warning(const char *title, const char *format, va_list args) { char *s; if (use_browser > 0 && vasprintf(&s, format, args) > 0) { + int key; + pthread_mutex_lock(&ui__lock); - ui__question_window(title, s, "Press any key...", 0); + key = ui__question_window(title, s, "Press any key...", 0); pthread_mutex_unlock(&ui__lock); free(s); - return; + return key; } fprintf(stderr, "%s:\n", title); vfprintf(stderr, format, args); + return K_ESC; } -void ui__warning(const char *format, ...) +int ui__warning(const char *format, ...) { + int key; va_list args; va_start(args, format); - __ui__warning("Warning", format, args); + key = __ui__warning("Warning", format, args); va_end(args); + return key; } -void ui__error(const char *format, ...) +int ui__error(const char *format, ...) { + int key; va_list args; va_start(args, format); - __ui__warning("Error", format, args); + key = __ui__warning("Error", format, args); va_end(args); + return key; } diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h index 9a25538d4735..2d1738bd71c8 100644 --- a/tools/perf/util/ui/util.h +++ b/tools/perf/util/ui/util.h @@ -1,13 +1,14 @@ #ifndef _PERF_UI_UTIL_H_ #define _PERF_UI_UTIL_H_ 1 -#include +#include int ui__getch(int delay_secs); int ui__popup_menu(int argc, char * const argv[]); int ui__help_window(const char *text); -bool ui__dialog_yesno(const char *msg); +int ui__dialog_yesno(const char *msg); int ui__question_window(const char *title, const char *text, const char *exit_msg, int delay_secs); +int __ui__warning(const char *title, const char *format, va_list args); #endif /* _PERF_UI_UTIL_H_ */ -- cgit v1.2.3 From 7b27509fc62686c53e9301560034e6b0b001174d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Oct 2011 12:15:04 -0200 Subject: perf hists browser: Warn about lost events Just like the old perf top --tui and the --stdio version. But because we have the initial menu to choose which event to show in a session with multiple events we can see how many chunks were lost in each of the event types, clarifying which events are being affected the most. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-47yyqbubmjzch2chezmb21m6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 37 +++++++++++++++++++--------- tools/perf/util/hist.h | 1 + tools/perf/util/session.c | 29 +++++++++++++++++----- tools/perf/util/top.h | 1 - tools/perf/util/ui/browser.c | 21 +++++++++++++--- tools/perf/util/ui/browser.h | 3 ++- tools/perf/util/ui/browsers/hists.c | 49 ++++++++++++++++++++++++++++++++----- 7 files changed, 112 insertions(+), 29 deletions(-) (limited to 'tools/perf/util/ui/browsers/hists.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31aa82c39e2a..8577bfeb087a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -89,6 +89,7 @@ static bool vmlinux_warned; static bool inherit = false; static int realtime_prio = 0; static bool group = false; +static bool sample_id_all_avail = true; static unsigned int mmap_pages = 128; static bool dump_symtab = false; @@ -289,11 +290,13 @@ static void print_sym_table(void) printf("%-*.*s\n", win_width, win_width, graph_dotted_line); - if (top.total_lost_warned != top.session->hists.stats.total_lost) { - top.total_lost_warned = top.session->hists.stats.total_lost; - color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); - printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", - top.total_lost_warned); + if (top.sym_evsel->hists.stats.nr_lost_warned != + top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { + top.sym_evsel->hists.stats.nr_lost_warned = + top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + color_fprintf(stdout, PERF_COLOR_RED, + "WARNING: LOST %d chunks, Check IO/CPU overload", + top.sym_evsel->hists.stats.nr_lost_warned); ++printed; } @@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) } static void perf_event__process_sample(const union perf_event *event, + struct perf_evsel *evsel, struct perf_sample *sample, struct perf_session *session) { @@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event, } if (al.sym == NULL || !al.sym->ignore) { - struct perf_evsel *evsel; struct hist_entry *he; - evsel = perf_evlist__id2evsel(top.evlist, sample->id); - assert(evsel != NULL); - if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = perf_session__resolve_callchain(session, al.thread, @@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event, static void perf_session__mmap_read_idx(struct perf_session *self, int idx) { struct perf_sample sample; + struct perf_evsel *evsel; union perf_event *event; int ret; @@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) continue; } + evsel = perf_evlist__id2evsel(self->evlist, sample.id); + assert(evsel != NULL); + if (event->header.type == PERF_RECORD_SAMPLE) - perf_event__process_sample(event, &sample, self); - else + perf_event__process_sample(event, evsel, &sample, self); + else if (event->header.type < PERF_RECORD_MAX) { + hists__inc_nr_events(&evsel->hists, event->header.type); perf_event__process(event, &sample, self); + } else + ++self->hists.stats.nr_unknown_events; } } @@ -864,6 +871,8 @@ static void start_counters(struct perf_evlist *evlist) attr->mmap = 1; attr->comm = 1; attr->inherit = inherit; +retry_sample_id: + attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: if (perf_evsel__open(counter, top.evlist->cpus, top.evlist->threads, group, @@ -873,6 +882,12 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; + } else if (err == EINVAL && sample_id_all_avail) { + /* + * Old kernel, no attr->sample_id_type_all field + */ + sample_id_all_avail = false; + goto retry_sample_id; } /* * If it's cycles then fall back to hrtimer diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff93ddc91c5c..c86c1d27bd1e 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -28,6 +28,7 @@ struct events_stats { u64 total_lost; u64 total_invalid_chains; u32 nr_events[PERF_RECORD_HEADER_MAX]; + u32 nr_lost_warned; u32 nr_unknown_events; u32 nr_invalid_chains; u32 nr_unknown_id; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 91c6442ef966..da354fe5e085 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -738,10 +738,27 @@ static int perf_session_deliver_event(struct perf_session *session, dump_event(session, event, file_offset, sample); + evsel = perf_evlist__id2evsel(session->evlist, sample->id); + if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) { + /* + * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here + * because the tools right now may apply filters, discarding + * some of the samples. For consistency, in the future we + * should have something like nr_filtered_samples and remove + * the sample->period from total_sample_period, etc, KISS for + * now tho. + * + * Also testing against NULL allows us to handle files without + * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the + * future probably it'll be a good idea to restrict event + * processing via perf_session to files with both set. + */ + hists__inc_nr_events(&evsel->hists, event->header.type); + } + switch (event->header.type) { case PERF_RECORD_SAMPLE: dump_sample(session, event, sample); - evsel = perf_evlist__id2evsel(session->evlist, sample->id); if (evsel == NULL) { ++session->hists.stats.nr_unknown_id; return -1; @@ -874,11 +891,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, const struct perf_event_ops *ops) { if (ops->lost == perf_event__process_lost && - session->hists.stats.total_lost != 0) { - ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 - "!\n\nCheck IO/CPU overload!\n\n", - session->hists.stats.total_period, - session->hists.stats.total_lost); + session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { + ui__warning("Processed %d events and lost %d chunks!\n\n" + "Check IO/CPU overload!\n\n", + session->hists.stats.nr_events[0], + session->hists.stats.nr_events[PERF_RECORD_LOST]); } if (session->hists.stats.nr_unknown_events != 0) { diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 01d1057f3074..399650967958 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -19,7 +19,6 @@ struct perf_top { u64 kernel_samples, us_samples; u64 exact_samples; u64 guest_us_samples, guest_kernel_samples; - u64 total_lost_warned; int print_entries, count_filter, delay_secs; int freq; pid_t target_pid, target_tid; diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index d2051be04f12..556829124b02 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -176,16 +176,29 @@ void ui_browser__handle_resize(struct ui_browser *browser) ui_browser__refresh(browser); } -int ui_browser__warning(struct ui_browser *browser, const char *format, ...) +int ui_browser__warning(struct ui_browser *browser, int timeout, + const char *format, ...) { va_list args; - int key; + char *text; + int key = 0, err; va_start(args, format); - while ((key = __ui__warning("Warning!", format, args)) == K_RESIZE) - ui_browser__handle_resize(browser); + err = vasprintf(&text, format, args); va_end(args); + if (err < 0) { + va_start(args, format); + ui_helpline__vpush(format, args); + va_end(args); + } else { + while ((key == ui__question_window("Warning!", text, + "Press any key...", + timeout)) == K_RESIZE) + ui_browser__handle_resize(browser); + free(text); + } + return key; } diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index fb1c59883e6a..84d761b730c1 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -45,7 +45,8 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs); void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); void ui_browser__handle_resize(struct ui_browser *browser); -int ui_browser__warning(struct ui_browser *browser, const char *format, ...); +int ui_browser__warning(struct ui_browser *browser, int timeout, + const char *format, ...); int ui_browser__help_window(struct ui_browser *browser, const char *text); bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index b8733c0770cd..d0c94b459685 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -295,6 +295,15 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold) ui_browser__reset_index(&self->b); } +static void ui_browser__warn_lost_events(struct ui_browser *browser) +{ + ui_browser__warning(browser, 4, + "Events are being lost, check IO/CPU overload!\n\n" + "You may want to run 'perf' using a RT scheduler policy:\n\n" + " perf top -r 80\n\n" + "Or reduce the sampling frequency."); +} + static int hist_browser__run(struct hist_browser *self, const char *ev_name, void(*timer)(void *arg), void *arg, int delay_secs) { @@ -318,8 +327,15 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, case K_TIMER: timer(arg); ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); - hists__browser_title(self->hists, title, sizeof(title), - ev_name); + + if (self->hists->stats.nr_lost_warned != + self->hists->stats.nr_events[PERF_RECORD_LOST]) { + self->hists->stats.nr_lost_warned = + self->hists->stats.nr_events[PERF_RECORD_LOST]; + ui_browser__warn_lost_events(&self->b); + } + + hists__browser_title(self->hists, title, sizeof(title), ev_name); ui_browser__show_title(&self->b, title); continue; case 'D': { /* Debug */ @@ -883,7 +899,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, goto out_free_stack; case 'a': if (!browser->has_symbols) { - ui_browser__warning(&browser->b, + ui_browser__warning(&browser->b, delay_secs * 2, "Annotation is only available for symbolic views, " "include \"sym\" in --sort to use it."); continue; @@ -1061,6 +1077,7 @@ out: struct perf_evsel_menu { struct ui_browser b; struct perf_evsel *selection; + bool lost_events, lost_events_warned; }; static void perf_evsel_menu__write(struct ui_browser *browser, @@ -1073,14 +1090,29 @@ static void perf_evsel_menu__write(struct ui_browser *browser, unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; const char *ev_name = event_name(evsel); char bf[256], unit; + const char *warn = " "; + size_t printed; ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : HE_COLORSET_NORMAL); nr_events = convert_unit(nr_events, &unit); - snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, - unit, unit == ' ' ? "" : " ", ev_name); - slsmg_write_nstring(bf, browser->width); + printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, + unit, unit == ' ' ? "" : " ", ev_name); + slsmg_printf("%s", bf); + + nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + if (nr_events != 0) { + menu->lost_events = true; + if (!current_entry) + ui_browser__set_color(browser, HE_COLORSET_TOP); + nr_events = convert_unit(nr_events, &unit); + snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, + unit, unit == ' ' ? "" : " "); + warn = bf; + } + + slsmg_write_nstring(warn, browser->width - printed); if (current_entry) menu->selection = evsel; @@ -1105,6 +1137,11 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, switch (key) { case K_TIMER: timer(arg); + + if (!menu->lost_events_warned && menu->lost_events) { + ui_browser__warn_lost_events(&menu->b); + menu->lost_events_warned = true; + } continue; case K_RIGHT: case K_ENTER: -- cgit v1.2.3