diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-top.c | 25 | ||||
-rw-r--r-- | tools/perf/perf.c | 24 | ||||
-rw-r--r-- | tools/perf/perf.h | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 24 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 11 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 | ||||
-rw-r--r-- | tools/perf/util/ui/browser.c | 228 | ||||
-rw-r--r-- | tools/perf/util/ui/browser.h | 10 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 95 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 110 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/map.c | 6 | ||||
-rw-r--r-- | tools/perf/util/ui/helpline.h | 2 |
13 files changed, 375 insertions, 165 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c5aebf6..e211304 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); } @@ -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 ec635b7..73d0cac 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 08b0b5e..914c895 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/header.c b/tools/perf/util/header.c index f2ceb0f..2143a32 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)) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 50c8fec..a7193c5 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -100,13 +100,15 @@ 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; 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; @@ -114,11 +116,15 @@ 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) + if (sort__need_collapse || threaded) rb_erase(&n->rb_node_in, &hists->entries_collapsed); hist_entry__free(n); @@ -127,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 7ea1e56..bcc8ab9 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); @@ -103,16 +104,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; } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 03851e3..3f67ae3 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/browser.c b/tools/perf/util/ui/browser.c index 611219f..a54b926 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 <newt.h> #include "ui.h" #include <linux/compiler.h> #include <linux/list.h> @@ -8,8 +11,8 @@ #include "browser.h" #include "helpline.h" #include "../color.h" -#include "../util.h" -#include <stdio.h> + +int newtGetKey(void); static int ui_browser__percent_color(double percent, bool current) { @@ -39,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; @@ -127,11 +161,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,26 +173,11 @@ 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) -{ - newtFormAddHotKey(self->form, key); -} - -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); 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,77 +190,143 @@ 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; } -int ui_browser__run(struct ui_browser *self) +/* + * 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->top = NULL; + browser->seek(browser, browser->top_idx, SEEK_SET); +} + +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; @@ -301,10 +383,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; } @@ -316,27 +396,29 @@ 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; } -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", @@ -346,7 +428,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 fc63dda..351c006 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 <stdbool.h> -#include <newt.h> #include <sys/types.h> #include "../types.h" @@ -13,14 +12,16 @@ #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); + bool (*filter)(struct ui_browser *self, void *entry); u32 nr_entries; }; @@ -32,15 +33,14 @@ 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, 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); unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 674b55e..eb2712e 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,20 +230,14 @@ 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 }; + 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; - ui_browser__add_exit_keys(&self->b, exit_keys); annotate_browser__calc_percent(self, evidx); if (self->curr_hot) @@ -196,11 +245,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); @@ -244,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) { @@ -295,8 +345,13 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, timer, arg, delay_secs); } break; - default: + case NEWT_KEY_LEFT: + case NEWT_KEY_ESCAPE: + case 'q': + case CTRL('c'): goto out; + default: + continue; } if (nd != NULL) @@ -329,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, }, }; @@ -356,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, diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index e64d952..b144b10 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -301,11 +301,7 @@ 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, - NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, }; self->b.entries = &self->hists->entries; self->b.nr_entries = self->hists->nr_entries; @@ -318,27 +314,14 @@ 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: /* 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); @@ -617,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); @@ -676,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)); @@ -931,8 +925,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) @@ -982,9 +979,14 @@ 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); else if (choice == zoom_dso) { @@ -1061,8 +1063,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, }; - int delay_msecs = delay_secs * 1000; struct perf_evlist *evlist = menu->b.priv; struct perf_evsel *pos; const char *ev_name, *title = "Available samples"; @@ -1072,13 +1072,8 @@ 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: @@ -1090,44 +1085,53 @@ 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_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); - 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'): goto out; default: - break; + continue; } } diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index 8462bff..6905bcc 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 <elf.h> +#include <newt.h> #include <inttypes.h> #include <sys/ttydefaults.h> #include <ctype.h> @@ -108,11 +109,8 @@ 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); + 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 ab6028d..8099757 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 <stdio.h> + void ui_helpline__init(void); void ui_helpline__pop(void); void ui_helpline__push(const char *msg); |