diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/newt.c | 129 |
1 files changed, 127 insertions, 2 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 91de99b5844..fc4a2b3aa65 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -13,6 +13,7 @@ #include <slang.h> #include <signal.h> #include <stdlib.h> +#include <elf.h> #include <newt.h> #include <sys/ttydefaults.h> @@ -280,6 +281,7 @@ struct ui_browser { u16 top, left, width, height; void *priv; unsigned int (*refresh_entries)(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); u32 nr_entries; @@ -316,6 +318,58 @@ static void ui_browser__list_head_seek(struct ui_browser *self, self->first_visible_entry = pos; } +static void ui_browser__rb_tree_seek(struct ui_browser *self, + off_t offset, int whence) +{ + struct rb_root *root = self->entries; + struct rb_node *nd; + + switch (whence) { + case SEEK_SET: + nd = rb_first(root); + break; + case SEEK_CUR: + nd = self->first_visible_entry; + break; + case SEEK_END: + nd = rb_last(root); + break; + default: + return; + } + + if (offset > 0) { + while (offset-- != 0) + nd = rb_next(nd); + } else { + while (offset++ != 0) + nd = rb_prev(nd); + } + + self->first_visible_entry = nd; +} + +static unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) +{ + struct rb_node *nd; + int row = 0; + + if (self->first_visible_entry == NULL) + self->first_visible_entry = rb_first(self->entries); + + nd = self->first_visible_entry; + + while (nd != NULL) { + SLsmg_gotorc(self->top + row, self->left); + self->write(self, nd, row); + if (++row == self->height) + break; + nd = rb_next(nd); + } + + return row; +} + static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) { return (self->first_visible_entry_idx + row) == self->index; @@ -592,6 +646,70 @@ int hist_entry__tui_annotate(struct hist_entry *self) return ret; } +/* -------------------------------------------------------------------- */ + +struct map_browser { + struct ui_browser b; + struct map *map; + u16 namelen; + u8 addrlen; +}; + +static void map_browser__write(struct ui_browser *self, void *nd, int row) +{ + struct symbol *sym = rb_entry(nd, struct symbol, rb_node); + struct map_browser *mb = container_of(self, struct map_browser, b); + bool current_entry = ui_browser__is_current_entry(self, row); + int color = ui_browser__percent_color(0, current_entry); + + SLsmg_set_color(color); + slsmg_printf("%*llx %*llx %c ", + mb->addrlen, sym->start, mb->addrlen, sym->end, + sym->binding == STB_GLOBAL ? 'g' : + sym->binding == STB_LOCAL ? 'l' : 'w'); + slsmg_write_nstring(sym->name, mb->namelen); +} + +static int map__browse(struct map *self) +{ + struct map_browser mb = { + .b = { + .entries = &self->dso->symbols[self->type], + .refresh_entries = ui_browser__rb_tree_refresh, + .seek = ui_browser__rb_tree_seek, + .write = map_browser__write, + }, + }; + struct newtExitStruct es; + struct rb_node *nd; + char tmp[BITS_PER_LONG / 4]; + u64 maxaddr = 0; + int ret; + + ui_helpline__push("Press <- or ESC to exit"); + + for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { + struct symbol *pos = rb_entry(nd, struct symbol, rb_node); + + if (mb.namelen < pos->namelen) + mb.namelen = pos->namelen; + if (maxaddr < pos->end) + maxaddr = pos->end; + ++mb.b.nr_entries; + } + + mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); + mb.b.width += mb.addrlen * 2 + 4 + mb.namelen; + ui_browser__show(&mb.b, self->dso->long_name); + ret = ui_browser__run(&mb.b, &es); + newtFormDestroy(mb.b.form); + newtPopWindow(); + ui_helpline__pop(); + return ret; +} + +/* -------------------------------------------------------------------- */ + struct hist_browser { struct ui_browser b; struct hists *hists; @@ -680,7 +798,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) const struct dso *dso; char *options[16]; int nr_options = 0, choice = 0, i, - annotate = -2, zoom_dso = -2, zoom_thread = -2; + annotate = -2, zoom_dso = -2, zoom_thread = -2, + browse_map = -2; if (hist_browser__run(browser, msg, &es)) break; @@ -771,6 +890,10 @@ do_help: (dso->kernel ? "the Kernel" : dso->short_name)) > 0) zoom_dso = nr_options++; + if (browser->selection->map != NULL && + asprintf(&options[nr_options], "Browse map details") > 0) + browse_map = nr_options++; + options[nr_options++] = (char *)"Exit"; choice = popup_menu(nr_options, options); @@ -800,7 +923,9 @@ do_annotate: continue; hist_entry__tui_annotate(he); - } else if (choice == zoom_dso) { + } 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); |