summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/ui/browsers/hists.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ui/browsers/hists.c')
-rw-r--r--tools/perf/util/ui/browsers/hists.c146
1 files changed, 100 insertions, 46 deletions
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622df..e64d9527f14 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -24,8 +24,15 @@ 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);
+
static void hist_browser__refresh_dimensions(struct hist_browser *self)
{
/* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +297,53 @@ 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 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 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,
+ NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, };
self->b.entries = &self->hists->entries;
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);
+ if (self->has_symbols)
+ ui_browser__add_exit_keys(&self->b, sym_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);
+ /*
+ * 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);
+ ui_browser__show_title(&self->b, title);
+ continue;
case 'D': { /* Debug */
static int seq;
struct hist_entry *h = rb_entry(self->b.top,
@@ -761,6 +793,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;
@@ -803,16 +836,15 @@ 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)
+ 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 +856,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 +864,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);
@@ -862,16 +892,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
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:
@@ -889,9 +920,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;
}
@@ -904,6 +935,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
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 &&
@@ -913,14 +947,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++;
@@ -928,7 +962,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
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);
@@ -949,45 +983,42 @@ 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);
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 +1057,12 @@ 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, };
+ 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 +1072,30 @@ 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, nr_events, help,
+ ev_name, true, timer,
+ arg, delay_secs);
ui_browser__show_title(&menu->b, title);
break;
case NEWT_KEY_LEFT:
@@ -1070,12 +1114,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'):
@@ -1091,7 +1137,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 +1169,24 @@ 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, evlist->nr_entries, 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, evlist->nr_entries, 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);
}