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') 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.2 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') 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.2 From 33e27312aeb05798572ccc456a76321125e8d7cb Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 12 Oct 2011 14:03:28 +0200 Subject: perf hists: Fix compilation when NO_NEWT_SUPPORT is set This patch, relative to tip/master, makes perf compile when NO_NEWT_SUPPORT is set. It also fixes the line formatting to fit 80 columns. Please test with NO_NEWT. Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20111012120328.GA1619@quad Signed-off-by: Stephane Eranian Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7ea1e560e008..7416521f7fea 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -103,16 +103,20 @@ struct perf_evlist; #ifdef NO_NEWT_SUPPORT static inline int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, - const char *help __used, void(*timer)(void *arg) __used, void *arg, + const char *help __used, + void(*timer)(void *arg) __used, + void *arg __used, int refresh __used) { return 0; } static inline int hist_entry__tui_annotate(struct hist_entry *self __used, - int evidx __used, int nr_events __used, + int evidx __used, + int nr_events __used, void(*timer)(void *arg) __used, - void *arg __used, int delay_secs __used); + void *arg __used, + int delay_secs __used) { return 0; } -- cgit v1.2.2 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') 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.2 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') 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.2 From e345fa185ad805cbd3be3397b3cba32bc42ef571 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Oct 2011 09:06:54 -0300 Subject: perf top: Remove entries from entries_collapsed on decay We were removing only when using a --sort order that needs collapsing, while we also use it in the threaded case, causing memory corruption because we were scribbling freed hist entries, oops. 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-k16fb4jsulr7x0ixv43amb6d@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++-- tools/perf/util/hist.c | 14 ++++++++++++-- tools/perf/util/hist.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index de3cb1e00f9e..e211304a0dd7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -304,7 +304,7 @@ static void print_sym_table(void) hists__collapse_resort_threaded(&top.sym_evsel->hists); hists__output_resort_threaded(&top.sym_evsel->hists); - hists__decay_entries(&top.sym_evsel->hists); + hists__decay_entries_threaded(&top.sym_evsel->hists); hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); putchar('\n'); hists__fprintf(&top.sym_evsel->hists, NULL, false, false, @@ -555,7 +555,7 @@ static void perf_top__sort_new_samples(void *arg) hists__collapse_resort_threaded(&t->sym_evsel->hists); hists__output_resort_threaded(&t->sym_evsel->hists); - hists__decay_entries(&t->sym_evsel->hists); + hists__decay_entries_threaded(&t->sym_evsel->hists); hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3); } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9b9d12bbdc1d..a7193c5a0422 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -108,7 +108,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) return he->period == 0; } -void hists__decay_entries(struct hists *hists) +static void __hists__decay_entries(struct hists *hists, bool threaded) { struct rb_node *next = rb_first(&hists->entries); struct hist_entry *n; @@ -124,7 +124,7 @@ void hists__decay_entries(struct hists *hists) if (hists__decay_entry(hists, n) && !n->used) { rb_erase(&n->rb_node, &hists->entries); - if (sort__need_collapse) + if (sort__need_collapse || threaded) rb_erase(&n->rb_node_in, &hists->entries_collapsed); hist_entry__free(n); @@ -133,6 +133,16 @@ void hists__decay_entries(struct hists *hists) } } +void hists__decay_entries(struct hists *hists) +{ + return __hists__decay_entries(hists, false); +} + +void hists__decay_entries_threaded(struct hists *hists) +{ + return __hists__decay_entries(hists, true); +} + /* * histogram, sorted on item, collects periods */ diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7416521f7fea..bcc8ab91e26f 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -79,6 +79,7 @@ void hists__collapse_resort(struct hists *self); void hists__collapse_resort_threaded(struct hists *hists); void hists__decay_entries(struct hists *hists); +void hists__decay_entries_threaded(struct hists *hists); void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__inc_nr_events(struct hists *self, u32 type); -- cgit v1.2.2 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') 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.2 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') 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.2 From 7296d66aca60a71076a5f0ffab39730e7788590f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Oct 2011 09:37:38 -0300 Subject: perf annotate browser: Exit when pressing ESC or the left arrow We lost that functionality on ed7e566, restore 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-z8eb8af2x46x42lgpn1ustid@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index cbefb4fc99c4..84315c999284 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -285,6 +285,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, timer, arg, delay_secs); } break; + case NEWT_KEY_LEFT: + case NEWT_KEY_ESCAPE: case 'q': case CTRL('c'): goto out; -- cgit v1.2.2 From 250611cfb60ff0c50ca189da7ca727dcd78e8cee Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Oct 2011 12:27:54 -0300 Subject: perf ui browser: Add filter method Its becoming common to allow the user to filter out parts of the data structure being browsed, like already done in the hists browser and in the annotate browser in the next commit, so provide it directly in the ui_browser class list_head helpers. More work required to move the equivalent routines found now in the hists browser to the rb_tree helpers. 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-jk7danyt1d9ji4e3o2xuthpn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browser.c | 51 ++++++++++++++++++++++++++++++++++++-------- tools/perf/util/ui/browser.h | 1 + 2 files changed, 43 insertions(+), 9 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 078ceaf5f8c1..a54b926efe2b 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -42,31 +42,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x) SLsmg_gotorc(self->y + y, self->x + x); } +static struct list_head * +ui_browser__list_head_filter_entries(struct ui_browser *browser, + struct list_head *pos) +{ + do { + if (!browser->filter || !browser->filter(browser, pos)) + return pos; + pos = pos->next; + } while (pos != browser->entries); + + return NULL; +} + +static struct list_head * +ui_browser__list_head_filter_prev_entries(struct ui_browser *browser, + struct list_head *pos) +{ + do { + if (!browser->filter || !browser->filter(browser, pos)) + return pos; + pos = pos->prev; + } while (pos != browser->entries); + + return NULL; +} + void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) { struct list_head *head = self->entries; struct list_head *pos; + if (self->nr_entries == 0) + return; + switch (whence) { case SEEK_SET: - pos = head->next; + pos = ui_browser__list_head_filter_entries(self, head->next); break; case SEEK_CUR: pos = self->top; break; case SEEK_END: - pos = head->prev; + pos = ui_browser__list_head_filter_prev_entries(self, head->prev); break; default: return; } + assert(pos != NULL); + if (offset > 0) { while (offset-- != 0) - pos = pos->next; + pos = ui_browser__list_head_filter_entries(self, pos->next); } else { while (offset++ != 0) - pos = pos->prev; + pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); } self->top = pos; @@ -365,15 +396,17 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self) int row = 0; if (self->top == NULL || self->top == self->entries) - self->top = head->next; + self->top = ui_browser__list_head_filter_entries(self, head->next); pos = self->top; list_for_each_from(pos, head) { - ui_browser__gotorc(self, row, 0); - self->write(self, pos, row); - if (++row == self->height) - break; + if (!self->filter || !self->filter(self, pos)) { + ui_browser__gotorc(self, row, 0); + self->write(self, pos, row); + if (++row == self->height) + break; + } } return row; diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 7dd9d6107d12..351c006dd4b5 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -21,6 +21,7 @@ struct ui_browser { 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); + bool (*filter)(struct ui_browser *self, void *entry); u32 nr_entries; }; -- cgit v1.2.2 From 0361fc25d509be09464dd23c274bd175cc933cc8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Oct 2011 12:31:21 -0300 Subject: perf annotate browser: Allow toggling the visualization of source code lines Just press 'S' on any assembly line and the source code will be hidden while the current line remains selected. Press 'S' again to show them back. 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-efmxm5etouebb7es0kkyqqwa@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 76 +++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 84315c999284..eb2712ecb601 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -21,12 +21,16 @@ struct annotate_browser { struct rb_root entries; struct rb_node *curr_hot; struct objdump_line *selection; + int nr_asm_entries; + int nr_entries; + bool hide_src_code; }; struct objdump_line_rb_node { struct rb_node rb_node; double percent; u32 idx; + int idx_asm; }; static inline @@ -35,10 +39,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) return (struct objdump_line_rb_node *)(self + 1); } +static bool objdump_line__filter(struct ui_browser *browser, void *entry) +{ + struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); + + if (ab->hide_src_code) { + struct objdump_line *ol = list_entry(entry, struct objdump_line, node); + return ol->offset == -1; + } + + return false; +} + 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); + struct objdump_line *ol = list_entry(entry, struct objdump_line, node); bool current_entry = ui_browser__is_current_entry(self, row); int width = self->width; @@ -168,6 +184,45 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, browser->curr_hot = rb_last(&browser->entries); } +static bool annotate_browser__toggle_source(struct annotate_browser *browser) +{ + struct objdump_line *ol; + struct objdump_line_rb_node *olrb; + off_t offset = browser->b.index - browser->b.top_idx; + + browser->b.seek(&browser->b, offset, SEEK_CUR); + ol = list_entry(browser->b.top, struct objdump_line, node); + olrb = objdump_line__rb(ol); + + if (browser->hide_src_code) { + if (olrb->idx_asm < offset) + offset = olrb->idx; + + browser->b.nr_entries = browser->nr_entries; + browser->hide_src_code = false; + browser->b.seek(&browser->b, -offset, SEEK_CUR); + browser->b.top_idx = olrb->idx - offset; + browser->b.index = olrb->idx; + } else { + if (olrb->idx_asm < 0) { + ui_helpline__puts("Only available for assembly lines."); + browser->b.seek(&browser->b, -offset, SEEK_CUR); + return false; + } + + if (olrb->idx_asm < offset) + offset = olrb->idx_asm; + + browser->b.nr_entries = browser->nr_asm_entries; + browser->hide_src_code = true; + browser->b.seek(&browser->b, -offset, SEEK_CUR); + browser->b.top_idx = olrb->idx_asm - offset; + browser->b.index = olrb->idx_asm; + } + + return true; +} + static int annotate_browser__run(struct annotate_browser *self, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs) @@ -175,11 +230,12 @@ 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; + const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, " + "H: Hottest, -> Line action, S -> Toggle source " + "code view"; int key; - if (ui_browser__show(&self->b, sym->name, - "<- or ESC: exit, TAB/shift+TAB: " - "cycle hottest lines, H: Hottest, -> Line action") < 0) + if (ui_browser__show(&self->b, sym->name, help) < 0) return -1; annotate_browser__calc_percent(self, evidx); @@ -234,6 +290,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, case 'H': nd = self->curr_hot; break; + case 'S': + if (annotate_browser__toggle_source(self)) + ui_helpline__puts(help); + continue; case NEWT_KEY_ENTER: case NEWT_KEY_RIGHT: if (self->selection == NULL) { @@ -324,6 +384,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, + .filter = objdump_line__filter, .priv = &ms, }, }; @@ -351,9 +412,14 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, if (browser.b.width < line_len) browser.b.width = line_len; rbpos = objdump_line__rb(pos); - rbpos->idx = browser.b.nr_entries++; + rbpos->idx = browser.nr_entries++; + if (pos->offset != -1) + rbpos->idx_asm = browser.nr_asm_entries++; + else + rbpos->idx_asm = -1; } + browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ ret = annotate_browser__run(&browser, evidx, nr_events, -- cgit v1.2.2 From 6c3c5b26d08569ed80e10d3e02d3c997ed1e6e7c Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Fri, 14 Oct 2011 19:00:47 +0200 Subject: perf buildid: Fix possible unterminated readlink() result buffer The readlink function doesn't guarantee that a '\0' will be put at the end of the provided buffer if there is no space left. No need to do "buf[len] = '\0';" since the buffer is allocated with zalloc(). Link: http://lkml.kernel.org/r/4E986ABF.9040706@intra2net.com Signed-off-by: Thomas Jarosch Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f2ceb0f7d669..2143a32638c2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1289,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) if (access(linkname, F_OK)) goto out_free; - if (readlink(linkname, filename, size) < 0) + if (readlink(linkname, filename, size - 1) < 0) goto out_free; if (unlink(linkname)) -- cgit v1.2.2