diff options
Diffstat (limited to 'tools')
-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 91de99b58445..fc4a2b3aa65e 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <slang.h> | 13 | #include <slang.h> |
14 | #include <signal.h> | 14 | #include <signal.h> |
15 | #include <stdlib.h> | 15 | #include <stdlib.h> |
16 | #include <elf.h> | ||
16 | #include <newt.h> | 17 | #include <newt.h> |
17 | #include <sys/ttydefaults.h> | 18 | #include <sys/ttydefaults.h> |
18 | 19 | ||
@@ -280,6 +281,7 @@ struct ui_browser { | |||
280 | u16 top, left, width, height; | 281 | u16 top, left, width, height; |
281 | void *priv; | 282 | void *priv; |
282 | unsigned int (*refresh_entries)(struct ui_browser *self); | 283 | unsigned int (*refresh_entries)(struct ui_browser *self); |
284 | void (*write)(struct ui_browser *self, void *entry, int row); | ||
283 | void (*seek)(struct ui_browser *self, | 285 | void (*seek)(struct ui_browser *self, |
284 | off_t offset, int whence); | 286 | off_t offset, int whence); |
285 | u32 nr_entries; | 287 | u32 nr_entries; |
@@ -316,6 +318,58 @@ static void ui_browser__list_head_seek(struct ui_browser *self, | |||
316 | self->first_visible_entry = pos; | 318 | self->first_visible_entry = pos; |
317 | } | 319 | } |
318 | 320 | ||
321 | static void ui_browser__rb_tree_seek(struct ui_browser *self, | ||
322 | off_t offset, int whence) | ||
323 | { | ||
324 | struct rb_root *root = self->entries; | ||
325 | struct rb_node *nd; | ||
326 | |||
327 | switch (whence) { | ||
328 | case SEEK_SET: | ||
329 | nd = rb_first(root); | ||
330 | break; | ||
331 | case SEEK_CUR: | ||
332 | nd = self->first_visible_entry; | ||
333 | break; | ||
334 | case SEEK_END: | ||
335 | nd = rb_last(root); | ||
336 | break; | ||
337 | default: | ||
338 | return; | ||
339 | } | ||
340 | |||
341 | if (offset > 0) { | ||
342 | while (offset-- != 0) | ||
343 | nd = rb_next(nd); | ||
344 | } else { | ||
345 | while (offset++ != 0) | ||
346 | nd = rb_prev(nd); | ||
347 | } | ||
348 | |||
349 | self->first_visible_entry = nd; | ||
350 | } | ||
351 | |||
352 | static unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) | ||
353 | { | ||
354 | struct rb_node *nd; | ||
355 | int row = 0; | ||
356 | |||
357 | if (self->first_visible_entry == NULL) | ||
358 | self->first_visible_entry = rb_first(self->entries); | ||
359 | |||
360 | nd = self->first_visible_entry; | ||
361 | |||
362 | while (nd != NULL) { | ||
363 | SLsmg_gotorc(self->top + row, self->left); | ||
364 | self->write(self, nd, row); | ||
365 | if (++row == self->height) | ||
366 | break; | ||
367 | nd = rb_next(nd); | ||
368 | } | ||
369 | |||
370 | return row; | ||
371 | } | ||
372 | |||
319 | static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | 373 | static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) |
320 | { | 374 | { |
321 | return (self->first_visible_entry_idx + row) == self->index; | 375 | return (self->first_visible_entry_idx + row) == self->index; |
@@ -592,6 +646,70 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
592 | return ret; | 646 | return ret; |
593 | } | 647 | } |
594 | 648 | ||
649 | /* -------------------------------------------------------------------- */ | ||
650 | |||
651 | struct map_browser { | ||
652 | struct ui_browser b; | ||
653 | struct map *map; | ||
654 | u16 namelen; | ||
655 | u8 addrlen; | ||
656 | }; | ||
657 | |||
658 | static void map_browser__write(struct ui_browser *self, void *nd, int row) | ||
659 | { | ||
660 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); | ||
661 | struct map_browser *mb = container_of(self, struct map_browser, b); | ||
662 | bool current_entry = ui_browser__is_current_entry(self, row); | ||
663 | int color = ui_browser__percent_color(0, current_entry); | ||
664 | |||
665 | SLsmg_set_color(color); | ||
666 | slsmg_printf("%*llx %*llx %c ", | ||
667 | mb->addrlen, sym->start, mb->addrlen, sym->end, | ||
668 | sym->binding == STB_GLOBAL ? 'g' : | ||
669 | sym->binding == STB_LOCAL ? 'l' : 'w'); | ||
670 | slsmg_write_nstring(sym->name, mb->namelen); | ||
671 | } | ||
672 | |||
673 | static int map__browse(struct map *self) | ||
674 | { | ||
675 | struct map_browser mb = { | ||
676 | .b = { | ||
677 | .entries = &self->dso->symbols[self->type], | ||
678 | .refresh_entries = ui_browser__rb_tree_refresh, | ||
679 | .seek = ui_browser__rb_tree_seek, | ||
680 | .write = map_browser__write, | ||
681 | }, | ||
682 | }; | ||
683 | struct newtExitStruct es; | ||
684 | struct rb_node *nd; | ||
685 | char tmp[BITS_PER_LONG / 4]; | ||
686 | u64 maxaddr = 0; | ||
687 | int ret; | ||
688 | |||
689 | ui_helpline__push("Press <- or ESC to exit"); | ||
690 | |||
691 | for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { | ||
692 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
693 | |||
694 | if (mb.namelen < pos->namelen) | ||
695 | mb.namelen = pos->namelen; | ||
696 | if (maxaddr < pos->end) | ||
697 | maxaddr = pos->end; | ||
698 | ++mb.b.nr_entries; | ||
699 | } | ||
700 | |||
701 | mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); | ||
702 | mb.b.width += mb.addrlen * 2 + 4 + mb.namelen; | ||
703 | ui_browser__show(&mb.b, self->dso->long_name); | ||
704 | ret = ui_browser__run(&mb.b, &es); | ||
705 | newtFormDestroy(mb.b.form); | ||
706 | newtPopWindow(); | ||
707 | ui_helpline__pop(); | ||
708 | return ret; | ||
709 | } | ||
710 | |||
711 | /* -------------------------------------------------------------------- */ | ||
712 | |||
595 | struct hist_browser { | 713 | struct hist_browser { |
596 | struct ui_browser b; | 714 | struct ui_browser b; |
597 | struct hists *hists; | 715 | struct hists *hists; |
@@ -680,7 +798,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
680 | const struct dso *dso; | 798 | const struct dso *dso; |
681 | char *options[16]; | 799 | char *options[16]; |
682 | int nr_options = 0, choice = 0, i, | 800 | int nr_options = 0, choice = 0, i, |
683 | annotate = -2, zoom_dso = -2, zoom_thread = -2; | 801 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
802 | browse_map = -2; | ||
684 | 803 | ||
685 | if (hist_browser__run(browser, msg, &es)) | 804 | if (hist_browser__run(browser, msg, &es)) |
686 | break; | 805 | break; |
@@ -771,6 +890,10 @@ do_help: | |||
771 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) | 890 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) |
772 | zoom_dso = nr_options++; | 891 | zoom_dso = nr_options++; |
773 | 892 | ||
893 | if (browser->selection->map != NULL && | ||
894 | asprintf(&options[nr_options], "Browse map details") > 0) | ||
895 | browse_map = nr_options++; | ||
896 | |||
774 | options[nr_options++] = (char *)"Exit"; | 897 | options[nr_options++] = (char *)"Exit"; |
775 | 898 | ||
776 | choice = popup_menu(nr_options, options); | 899 | choice = popup_menu(nr_options, options); |
@@ -800,7 +923,9 @@ do_annotate: | |||
800 | continue; | 923 | continue; |
801 | 924 | ||
802 | hist_entry__tui_annotate(he); | 925 | hist_entry__tui_annotate(he); |
803 | } else if (choice == zoom_dso) { | 926 | } else if (choice == browse_map) |
927 | map__browse(browser->selection->map); | ||
928 | else if (choice == zoom_dso) { | ||
804 | zoom_dso: | 929 | zoom_dso: |
805 | if (dso_filter) { | 930 | if (dso_filter) { |
806 | pstack__remove(fstack, &dso_filter); | 931 | pstack__remove(fstack, &dso_filter); |