diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 18:23:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 18:23:47 -0400 |
commit | c5617b200ac52e35f7e8cf05a17b0a2d50f6b3e9 (patch) | |
tree | 40d5e99660c77c5791392d349a93113c044dbf14 /tools/perf/util/newt.c | |
parent | cad719d86e9dbd06634eaba6401e022c8101d6b2 (diff) | |
parent | 49c177461bfbedeccbab22bf3905db2f9da7f1c3 (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (61 commits)
tracing: Add __used annotation to event variable
perf, trace: Fix !x86 build bug
perf report: Support multiple events on the TUI
perf annotate: Fix up usage of the build id cache
x86/mmiotrace: Remove redundant instruction prefix checks
perf annotate: Add TUI interface
perf tui: Remove annotate from popup menu after failure
perf report: Don't start the TUI if -D is used
perf: Fix getline undeclared
perf: Optimize perf_tp_event_match()
perf: Remove more code from the fastpath
perf: Optimize the !vmalloc backed buffer
perf: Optimize perf_output_copy()
perf: Fix wakeup storm for RO mmap()s
perf-record: Share per-cpu buffers
perf-record: Remove -M
perf: Ensure that IOC_OUTPUT isn't used to create multi-writer buffers
perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events
perf, trace: Optimize tracepoints by removing IRQ-disable from perf/tracepoint interaction
perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig
...
Diffstat (limited to 'tools/perf/util/newt.c')
-rw-r--r-- | tools/perf/util/newt.c | 150 |
1 files changed, 116 insertions, 34 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index ccb7c5bb269e..d54c540f49db 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
@@ -1,7 +1,15 @@ | |||
1 | #define _GNU_SOURCE | 1 | #define _GNU_SOURCE |
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #undef _GNU_SOURCE | 3 | #undef _GNU_SOURCE |
4 | 4 | /* | |
5 | * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks | ||
6 | * the build if it isn't defined. Use the equivalent one that glibc | ||
7 | * has on features.h. | ||
8 | */ | ||
9 | #include <features.h> | ||
10 | #ifndef HAVE_LONG_LONG | ||
11 | #define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG | ||
12 | #endif | ||
5 | #include <slang.h> | 13 | #include <slang.h> |
6 | #include <stdlib.h> | 14 | #include <stdlib.h> |
7 | #include <newt.h> | 15 | #include <newt.h> |
@@ -227,6 +235,15 @@ static bool dialog_yesno(const char *msg) | |||
227 | return newtWinChoice(NULL, yes, no, (char *)msg) == 1; | 235 | return newtWinChoice(NULL, yes, no, (char *)msg) == 1; |
228 | } | 236 | } |
229 | 237 | ||
238 | static void ui__error_window(const char *fmt, ...) | ||
239 | { | ||
240 | va_list ap; | ||
241 | |||
242 | va_start(ap, fmt); | ||
243 | newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap); | ||
244 | va_end(ap); | ||
245 | } | ||
246 | |||
230 | #define HE_COLORSET_TOP 50 | 247 | #define HE_COLORSET_TOP 50 |
231 | #define HE_COLORSET_MEDIUM 51 | 248 | #define HE_COLORSET_MEDIUM 51 |
232 | #define HE_COLORSET_NORMAL 52 | 249 | #define HE_COLORSET_NORMAL 52 |
@@ -375,8 +392,11 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
375 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); | 392 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); |
376 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); | 393 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); |
377 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); | 394 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); |
395 | newtFormAddHotKey(self->form, ' '); | ||
378 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); | 396 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); |
379 | newtFormAddHotKey(self->form, NEWT_KEY_END); | 397 | newtFormAddHotKey(self->form, NEWT_KEY_END); |
398 | newtFormAddHotKey(self->form, NEWT_KEY_TAB); | ||
399 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); | ||
380 | 400 | ||
381 | if (ui_browser__refresh_entries(self) < 0) | 401 | if (ui_browser__refresh_entries(self) < 0) |
382 | return -1; | 402 | return -1; |
@@ -389,6 +409,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
389 | 409 | ||
390 | if (es->reason != NEWT_EXIT_HOTKEY) | 410 | if (es->reason != NEWT_EXIT_HOTKEY) |
391 | break; | 411 | break; |
412 | if (is_exit_key(es->u.key)) | ||
413 | return es->u.key; | ||
392 | switch (es->u.key) { | 414 | switch (es->u.key) { |
393 | case NEWT_KEY_DOWN: | 415 | case NEWT_KEY_DOWN: |
394 | if (self->index == self->nr_entries - 1) | 416 | if (self->index == self->nr_entries - 1) |
@@ -411,6 +433,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
411 | } | 433 | } |
412 | break; | 434 | break; |
413 | case NEWT_KEY_PGDN: | 435 | case NEWT_KEY_PGDN: |
436 | case ' ': | ||
414 | if (self->first_visible_entry_idx + self->height > self->nr_entries - 1) | 437 | if (self->first_visible_entry_idx + self->height > self->nr_entries - 1) |
415 | break; | 438 | break; |
416 | 439 | ||
@@ -461,12 +484,10 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
461 | } | 484 | } |
462 | } | 485 | } |
463 | break; | 486 | break; |
464 | case NEWT_KEY_ESCAPE: | 487 | case NEWT_KEY_RIGHT: |
465 | case NEWT_KEY_LEFT: | 488 | case NEWT_KEY_LEFT: |
466 | case CTRL('c'): | 489 | case NEWT_KEY_TAB: |
467 | case 'Q': | 490 | return es->u.key; |
468 | case 'q': | ||
469 | return 0; | ||
470 | default: | 491 | default: |
471 | continue; | 492 | continue; |
472 | } | 493 | } |
@@ -658,18 +679,24 @@ static size_t hist_entry__append_browser(struct hist_entry *self, | |||
658 | return ret; | 679 | return ret; |
659 | } | 680 | } |
660 | 681 | ||
661 | static void hist_entry__annotate_browser(struct hist_entry *self) | 682 | int hist_entry__tui_annotate(struct hist_entry *self) |
662 | { | 683 | { |
663 | struct ui_browser browser; | 684 | struct ui_browser browser; |
664 | struct newtExitStruct es; | 685 | struct newtExitStruct es; |
665 | struct objdump_line *pos, *n; | 686 | struct objdump_line *pos, *n; |
666 | LIST_HEAD(head); | 687 | LIST_HEAD(head); |
688 | int ret; | ||
667 | 689 | ||
668 | if (self->ms.sym == NULL) | 690 | if (self->ms.sym == NULL) |
669 | return; | 691 | return -1; |
670 | 692 | ||
671 | if (hist_entry__annotate(self, &head) < 0) | 693 | if (self->ms.map->dso->annotate_warned) |
672 | return; | 694 | return -1; |
695 | |||
696 | if (hist_entry__annotate(self, &head) < 0) { | ||
697 | ui__error_window(browser__last_msg); | ||
698 | return -1; | ||
699 | } | ||
673 | 700 | ||
674 | ui_helpline__push("Press <- or ESC to exit"); | 701 | ui_helpline__push("Press <- or ESC to exit"); |
675 | 702 | ||
@@ -684,7 +711,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) | |||
684 | } | 711 | } |
685 | 712 | ||
686 | browser.width += 18; /* Percentage */ | 713 | browser.width += 18; /* Percentage */ |
687 | ui_browser__run(&browser, self->ms.sym->name, &es); | 714 | ret = ui_browser__run(&browser, self->ms.sym->name, &es); |
688 | newtFormDestroy(browser.form); | 715 | newtFormDestroy(browser.form); |
689 | newtPopWindow(); | 716 | newtPopWindow(); |
690 | list_for_each_entry_safe(pos, n, &head, node) { | 717 | list_for_each_entry_safe(pos, n, &head, node) { |
@@ -692,6 +719,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) | |||
692 | objdump_line__free(pos); | 719 | objdump_line__free(pos); |
693 | } | 720 | } |
694 | ui_helpline__pop(); | 721 | ui_helpline__pop(); |
722 | return ret; | ||
695 | } | 723 | } |
696 | 724 | ||
697 | static const void *newt__symbol_tree_get_current(newtComponent self) | 725 | static const void *newt__symbol_tree_get_current(newtComponent self) |
@@ -814,6 +842,8 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists | |||
814 | newtFormAddHotKey(self->form, 'h'); | 842 | newtFormAddHotKey(self->form, 'h'); |
815 | newtFormAddHotKey(self->form, NEWT_KEY_F1); | 843 | newtFormAddHotKey(self->form, NEWT_KEY_F1); |
816 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); | 844 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); |
845 | newtFormAddHotKey(self->form, NEWT_KEY_TAB); | ||
846 | newtFormAddHotKey(self->form, NEWT_KEY_UNTAB); | ||
817 | newtFormAddComponents(self->form, self->tree, NULL); | 847 | newtFormAddComponents(self->form, self->tree, NULL); |
818 | self->selection = newt__symbol_tree_get_current(self->tree); | 848 | self->selection = newt__symbol_tree_get_current(self->tree); |
819 | 849 | ||
@@ -845,7 +875,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) | |||
845 | return he ? he->thread : NULL; | 875 | return he ? he->thread : NULL; |
846 | } | 876 | } |
847 | 877 | ||
848 | static int hist_browser__title(char *bf, size_t size, const char *input_name, | 878 | static int hist_browser__title(char *bf, size_t size, const char *ev_name, |
849 | const struct dso *dso, const struct thread *thread) | 879 | const struct dso *dso, const struct thread *thread) |
850 | { | 880 | { |
851 | int printed = 0; | 881 | int printed = 0; |
@@ -859,18 +889,18 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name, | |||
859 | printed += snprintf(bf + printed, size - printed, | 889 | printed += snprintf(bf + printed, size - printed, |
860 | "%sDSO: %s", thread ? " " : "", | 890 | "%sDSO: %s", thread ? " " : "", |
861 | dso->short_name); | 891 | dso->short_name); |
862 | return printed ?: snprintf(bf, size, "Report: %s", input_name); | 892 | return printed ?: snprintf(bf, size, "Event: %s", ev_name); |
863 | } | 893 | } |
864 | 894 | ||
865 | int hists__browse(struct hists *self, const char *helpline, const char *input_name) | 895 | int hists__browse(struct hists *self, const char *helpline, const char *ev_name) |
866 | { | 896 | { |
867 | struct hist_browser *browser = hist_browser__new(); | 897 | struct hist_browser *browser = hist_browser__new(); |
868 | struct pstack *fstack = pstack__new(2); | 898 | struct pstack *fstack; |
869 | const struct thread *thread_filter = NULL; | 899 | const struct thread *thread_filter = NULL; |
870 | const struct dso *dso_filter = NULL; | 900 | const struct dso *dso_filter = NULL; |
871 | struct newtExitStruct es; | 901 | struct newtExitStruct es; |
872 | char msg[160]; | 902 | char msg[160]; |
873 | int err = -1; | 903 | int key = -1; |
874 | 904 | ||
875 | if (browser == NULL) | 905 | if (browser == NULL) |
876 | return -1; | 906 | return -1; |
@@ -881,7 +911,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na | |||
881 | 911 | ||
882 | ui_helpline__push(helpline); | 912 | ui_helpline__push(helpline); |
883 | 913 | ||
884 | hist_browser__title(msg, sizeof(msg), input_name, | 914 | hist_browser__title(msg, sizeof(msg), ev_name, |
885 | dso_filter, thread_filter); | 915 | dso_filter, thread_filter); |
886 | if (hist_browser__populate(browser, self, msg) < 0) | 916 | if (hist_browser__populate(browser, self, msg) < 0) |
887 | goto out_free_stack; | 917 | goto out_free_stack; |
@@ -899,11 +929,27 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na | |||
899 | dso = browser->selection->map ? browser->selection->map->dso : NULL; | 929 | dso = browser->selection->map ? browser->selection->map->dso : NULL; |
900 | 930 | ||
901 | if (es.reason == NEWT_EXIT_HOTKEY) { | 931 | if (es.reason == NEWT_EXIT_HOTKEY) { |
902 | if (es.u.key == NEWT_KEY_F1) | 932 | key = es.u.key; |
933 | |||
934 | switch (key) { | ||
935 | case NEWT_KEY_F1: | ||
903 | goto do_help; | 936 | goto do_help; |
937 | case NEWT_KEY_TAB: | ||
938 | case NEWT_KEY_UNTAB: | ||
939 | /* | ||
940 | * Exit the browser, let hists__browser_tree | ||
941 | * go to the next or previous | ||
942 | */ | ||
943 | goto out_free_stack; | ||
944 | default:; | ||
945 | } | ||
904 | 946 | ||
905 | switch (toupper(es.u.key)) { | 947 | key = toupper(key); |
948 | switch (key) { | ||
906 | case 'A': | 949 | case 'A': |
950 | if (browser->selection->map == NULL && | ||
951 | browser->selection->map->dso->annotate_warned) | ||
952 | continue; | ||
907 | goto do_annotate; | 953 | goto do_annotate; |
908 | case 'D': | 954 | case 'D': |
909 | goto zoom_dso; | 955 | goto zoom_dso; |
@@ -922,14 +968,14 @@ do_help: | |||
922 | continue; | 968 | continue; |
923 | default:; | 969 | default:; |
924 | } | 970 | } |
925 | if (toupper(es.u.key) == 'Q' || | 971 | if (is_exit_key(key)) { |
926 | es.u.key == CTRL('c')) | 972 | if (key == NEWT_KEY_ESCAPE) { |
927 | break; | 973 | if (dialog_yesno("Do you really want to exit?")) |
928 | if (es.u.key == NEWT_KEY_ESCAPE) { | 974 | break; |
929 | if (dialog_yesno("Do you really want to exit?")) | 975 | else |
976 | continue; | ||
977 | } else | ||
930 | break; | 978 | break; |
931 | else | ||
932 | continue; | ||
933 | } | 979 | } |
934 | 980 | ||
935 | if (es.u.key == NEWT_KEY_LEFT) { | 981 | if (es.u.key == NEWT_KEY_LEFT) { |
@@ -947,6 +993,7 @@ do_help: | |||
947 | } | 993 | } |
948 | 994 | ||
949 | if (browser->selection->sym != NULL && | 995 | if (browser->selection->sym != NULL && |
996 | !browser->selection->map->dso->annotate_warned && | ||
950 | asprintf(&options[nr_options], "Annotate %s", | 997 | asprintf(&options[nr_options], "Annotate %s", |
951 | browser->selection->sym->name) > 0) | 998 | browser->selection->sym->name) > 0) |
952 | annotate = nr_options++; | 999 | annotate = nr_options++; |
@@ -981,6 +1028,7 @@ do_help: | |||
981 | struct hist_entry *he; | 1028 | struct hist_entry *he; |
982 | do_annotate: | 1029 | do_annotate: |
983 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { | 1030 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { |
1031 | browser->selection->map->dso->annotate_warned = 1; | ||
984 | ui_helpline__puts("No vmlinux file found, can't " | 1032 | ui_helpline__puts("No vmlinux file found, can't " |
985 | "annotate with just a " | 1033 | "annotate with just a " |
986 | "kallsyms file"); | 1034 | "kallsyms file"); |
@@ -991,7 +1039,7 @@ do_annotate: | |||
991 | if (he == NULL) | 1039 | if (he == NULL) |
992 | continue; | 1040 | continue; |
993 | 1041 | ||
994 | hist_entry__annotate_browser(he); | 1042 | hist_entry__tui_annotate(he); |
995 | } else if (choice == zoom_dso) { | 1043 | } else if (choice == zoom_dso) { |
996 | zoom_dso: | 1044 | zoom_dso: |
997 | if (dso_filter) { | 1045 | if (dso_filter) { |
@@ -1008,7 +1056,7 @@ zoom_out_dso: | |||
1008 | pstack__push(fstack, &dso_filter); | 1056 | pstack__push(fstack, &dso_filter); |
1009 | } | 1057 | } |
1010 | hists__filter_by_dso(self, dso_filter); | 1058 | hists__filter_by_dso(self, dso_filter); |
1011 | hist_browser__title(msg, sizeof(msg), input_name, | 1059 | hist_browser__title(msg, sizeof(msg), ev_name, |
1012 | dso_filter, thread_filter); | 1060 | dso_filter, thread_filter); |
1013 | if (hist_browser__populate(browser, self, msg) < 0) | 1061 | if (hist_browser__populate(browser, self, msg) < 0) |
1014 | goto out; | 1062 | goto out; |
@@ -1027,18 +1075,49 @@ zoom_out_thread: | |||
1027 | pstack__push(fstack, &thread_filter); | 1075 | pstack__push(fstack, &thread_filter); |
1028 | } | 1076 | } |
1029 | hists__filter_by_thread(self, thread_filter); | 1077 | hists__filter_by_thread(self, thread_filter); |
1030 | hist_browser__title(msg, sizeof(msg), input_name, | 1078 | hist_browser__title(msg, sizeof(msg), ev_name, |
1031 | dso_filter, thread_filter); | 1079 | dso_filter, thread_filter); |
1032 | if (hist_browser__populate(browser, self, msg) < 0) | 1080 | if (hist_browser__populate(browser, self, msg) < 0) |
1033 | goto out; | 1081 | goto out; |
1034 | } | 1082 | } |
1035 | } | 1083 | } |
1036 | err = 0; | ||
1037 | out_free_stack: | 1084 | out_free_stack: |
1038 | pstack__delete(fstack); | 1085 | pstack__delete(fstack); |
1039 | out: | 1086 | out: |
1040 | hist_browser__delete(browser); | 1087 | hist_browser__delete(browser); |
1041 | return err; | 1088 | return key; |
1089 | } | ||
1090 | |||
1091 | int hists__tui_browse_tree(struct rb_root *self, const char *help) | ||
1092 | { | ||
1093 | struct rb_node *first = rb_first(self), *nd = first, *next; | ||
1094 | int key = 0; | ||
1095 | |||
1096 | while (nd) { | ||
1097 | struct hists *hists = rb_entry(nd, struct hists, rb_node); | ||
1098 | const char *ev_name = __event_name(hists->type, hists->config); | ||
1099 | |||
1100 | key = hists__browse(hists, help, ev_name); | ||
1101 | |||
1102 | if (is_exit_key(key)) | ||
1103 | break; | ||
1104 | |||
1105 | switch (key) { | ||
1106 | case NEWT_KEY_TAB: | ||
1107 | next = rb_next(nd); | ||
1108 | if (next) | ||
1109 | nd = next; | ||
1110 | break; | ||
1111 | case NEWT_KEY_UNTAB: | ||
1112 | if (nd == first) | ||
1113 | continue; | ||
1114 | nd = rb_prev(nd); | ||
1115 | default: | ||
1116 | break; | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | return key; | ||
1042 | } | 1121 | } |
1043 | 1122 | ||
1044 | static struct newtPercentTreeColors { | 1123 | static struct newtPercentTreeColors { |
@@ -1058,10 +1137,13 @@ static struct newtPercentTreeColors { | |||
1058 | void setup_browser(void) | 1137 | void setup_browser(void) |
1059 | { | 1138 | { |
1060 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; | 1139 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; |
1061 | if (!isatty(1)) | 1140 | |
1141 | if (!isatty(1) || !use_browser || dump_trace) { | ||
1142 | setup_pager(); | ||
1062 | return; | 1143 | return; |
1144 | } | ||
1063 | 1145 | ||
1064 | use_browser = true; | 1146 | use_browser = 1; |
1065 | newtInit(); | 1147 | newtInit(); |
1066 | newtCls(); | 1148 | newtCls(); |
1067 | ui_helpline__puts(" "); | 1149 | ui_helpline__puts(" "); |
@@ -1074,7 +1156,7 @@ void setup_browser(void) | |||
1074 | 1156 | ||
1075 | void exit_browser(bool wait_for_ok) | 1157 | void exit_browser(bool wait_for_ok) |
1076 | { | 1158 | { |
1077 | if (use_browser) { | 1159 | if (use_browser > 0) { |
1078 | if (wait_for_ok) { | 1160 | if (wait_for_ok) { |
1079 | char title[] = "Fatal Error", ok[] = "Ok"; | 1161 | char title[] = "Fatal Error", ok[] = "Ok"; |
1080 | newtWinMessage(title, ok, browser__last_msg); | 1162 | newtWinMessage(title, ok, browser__last_msg); |