diff options
| -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); |
