diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-06 11:07:30 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-06 11:14:53 -0500 |
commit | 7f0030b211579939461468f25b80c73e293c46e0 (patch) | |
tree | e0992d0a0c958526df603f9c18671a9612ff5b75 /tools/perf | |
parent | e248de331a452f8771eda6ed4bb30d92c82df28b (diff) |
perf report tui: Improve multi event session support
When multiple events were used in 'perf record', allow the user to
choose which one is wanted before showing the per event histograms.
Annotations will be performed on the chosen event.
Allow going back and forth from event to event quickly using just the
arrow keys and enter.
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: William Cohen <wcohen@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-report.c | 7 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 16 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 147 |
3 files changed, 140 insertions, 30 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1c399eae5f7b..e9b5d513333a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -222,7 +222,8 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, | |||
222 | return ret + fprintf(fp, "\n#\n"); | 222 | return ret + fprintf(fp, "\n#\n"); |
223 | } | 223 | } |
224 | 224 | ||
225 | static int hists__tty_browse_tree(struct perf_evlist *evlist, const char *help) | 225 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, |
226 | const char *help) | ||
226 | { | 227 | { |
227 | struct perf_evsel *pos; | 228 | struct perf_evsel *pos; |
228 | 229 | ||
@@ -304,9 +305,9 @@ static int __cmd_report(void) | |||
304 | } | 305 | } |
305 | 306 | ||
306 | if (use_browser > 0) | 307 | if (use_browser > 0) |
307 | hists__tui_browse_tree(session->evlist, help); | 308 | perf_evlist__tui_browse_hists(session->evlist, help); |
308 | else | 309 | else |
309 | hists__tty_browse_tree(session->evlist, help); | 310 | perf_evlist__tty_browse_hists(session->evlist, help); |
310 | 311 | ||
311 | out_delete: | 312 | out_delete: |
312 | /* | 313 | /* |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0d38b435827b..cb6858a2f9a3 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -87,15 +87,9 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); | |||
87 | struct perf_evlist; | 87 | struct perf_evlist; |
88 | 88 | ||
89 | #ifdef NO_NEWT_SUPPORT | 89 | #ifdef NO_NEWT_SUPPORT |
90 | static inline int hists__browse(struct hists *self __used, | 90 | static inline |
91 | const char *helpline __used, | 91 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, |
92 | const char *ev_name __used, int evidx __used) | 92 | const char *help __used) |
93 | { | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static inline int hists__tui_browse_tree(struct perf_evlist *evlist __used, | ||
98 | const char *help __used) | ||
99 | { | 93 | { |
100 | return 0; | 94 | return 0; |
101 | } | 95 | } |
@@ -109,14 +103,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, | |||
109 | #define KEY_RIGHT -2 | 103 | #define KEY_RIGHT -2 |
110 | #else | 104 | #else |
111 | #include <newt.h> | 105 | #include <newt.h> |
112 | int hists__browse(struct hists *self, const char *helpline, | ||
113 | const char *ev_name, int evidx); | ||
114 | int hist_entry__tui_annotate(struct hist_entry *self, int evidx); | 106 | int hist_entry__tui_annotate(struct hist_entry *self, int evidx); |
115 | 107 | ||
116 | #define KEY_LEFT NEWT_KEY_LEFT | 108 | #define KEY_LEFT NEWT_KEY_LEFT |
117 | #define KEY_RIGHT NEWT_KEY_RIGHT | 109 | #define KEY_RIGHT NEWT_KEY_RIGHT |
118 | 110 | ||
119 | int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help); | 111 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); |
120 | #endif | 112 | #endif |
121 | 113 | ||
122 | unsigned int hists__sort_list_width(struct hists *self); | 114 | unsigned int hists__sort_list_width(struct hists *self); |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index f3af4fe5cdc4..798efdca3ead 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -803,9 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, | |||
803 | return printed; | 803 | return printed; |
804 | } | 804 | } |
805 | 805 | ||
806 | int hists__browse(struct hists *self, const char *helpline, | 806 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, |
807 | const char *ev_name, int evidx) | 807 | const char *helpline, const char *ev_name, |
808 | bool left_exits) | ||
808 | { | 809 | { |
810 | struct hists *self = &evsel->hists; | ||
809 | struct hist_browser *browser = hist_browser__new(self); | 811 | struct hist_browser *browser = hist_browser__new(self); |
810 | struct pstack *fstack; | 812 | struct pstack *fstack; |
811 | const struct thread *thread_filter = NULL; | 813 | const struct thread *thread_filter = NULL; |
@@ -878,8 +880,14 @@ int hists__browse(struct hists *self, const char *helpline, | |||
878 | case NEWT_KEY_LEFT: { | 880 | case NEWT_KEY_LEFT: { |
879 | const void *top; | 881 | const void *top; |
880 | 882 | ||
881 | if (pstack__empty(fstack)) | 883 | if (pstack__empty(fstack)) { |
884 | /* | ||
885 | * Go back to the perf_evsel_menu__run or other user | ||
886 | */ | ||
887 | if (left_exits) | ||
888 | goto out_free_stack; | ||
882 | continue; | 889 | continue; |
890 | } | ||
883 | top = pstack__pop(fstack); | 891 | top = pstack__pop(fstack); |
884 | if (top == &dso_filter) | 892 | if (top == &dso_filter) |
885 | goto zoom_out_dso; | 893 | goto zoom_out_dso; |
@@ -888,7 +896,8 @@ int hists__browse(struct hists *self, const char *helpline, | |||
888 | continue; | 896 | continue; |
889 | } | 897 | } |
890 | case NEWT_KEY_ESCAPE: | 898 | case NEWT_KEY_ESCAPE: |
891 | if (!ui__dialog_yesno("Do you really want to exit?")) | 899 | if (!left_exits && |
900 | !ui__dialog_yesno("Do you really want to exit?")) | ||
892 | continue; | 901 | continue; |
893 | /* Fall thru */ | 902 | /* Fall thru */ |
894 | default: | 903 | default: |
@@ -940,7 +949,7 @@ do_annotate: | |||
940 | if (he == NULL) | 949 | if (he == NULL) |
941 | continue; | 950 | continue; |
942 | 951 | ||
943 | hist_entry__tui_annotate(he, evidx); | 952 | hist_entry__tui_annotate(he, evsel->idx); |
944 | } else if (choice == browse_map) | 953 | } else if (choice == browse_map) |
945 | map__browse(browser->selection->map); | 954 | map__browse(browser->selection->map); |
946 | else if (choice == zoom_dso) { | 955 | else if (choice == zoom_dso) { |
@@ -989,15 +998,71 @@ out: | |||
989 | return key; | 998 | return key; |
990 | } | 999 | } |
991 | 1000 | ||
992 | int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help) | 1001 | struct perf_evsel_menu { |
1002 | struct ui_browser b; | ||
1003 | struct perf_evsel *selection; | ||
1004 | }; | ||
1005 | |||
1006 | static void perf_evsel_menu__write(struct ui_browser *browser, | ||
1007 | void *entry, int row) | ||
1008 | { | ||
1009 | struct perf_evsel_menu *menu = container_of(browser, | ||
1010 | struct perf_evsel_menu, b); | ||
1011 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); | ||
1012 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
1013 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
1014 | const char *ev_name = event_name(evsel); | ||
1015 | char bf[256], unit; | ||
1016 | |||
1017 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | ||
1018 | HE_COLORSET_NORMAL); | ||
1019 | |||
1020 | nr_events = convert_unit(nr_events, &unit); | ||
1021 | snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | ||
1022 | unit, unit == ' ' ? "" : " ", ev_name); | ||
1023 | slsmg_write_nstring(bf, browser->width); | ||
1024 | |||
1025 | if (current_entry) | ||
1026 | menu->selection = evsel; | ||
1027 | } | ||
1028 | |||
1029 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) | ||
993 | { | 1030 | { |
1031 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
1032 | struct perf_evlist *evlist = menu->b.priv; | ||
994 | struct perf_evsel *pos; | 1033 | struct perf_evsel *pos; |
1034 | const char *ev_name, *title = "Available samples"; | ||
1035 | int key; | ||
995 | 1036 | ||
996 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | 1037 | if (ui_browser__show(&menu->b, title, |
997 | while (pos) { | 1038 | "ESC: exit, ENTER|->: Browse histograms") < 0) |
998 | struct hists *hists = &pos->hists; | 1039 | return -1; |
999 | const char *ev_name = event_name(pos); | 1040 | |
1000 | int key = hists__browse(hists, help, ev_name, pos->idx); | 1041 | ui_browser__add_exit_keys(&menu->b, exit_keys); |
1042 | |||
1043 | while (1) { | ||
1044 | key = ui_browser__run(&menu->b); | ||
1045 | |||
1046 | switch (key) { | ||
1047 | case NEWT_KEY_RIGHT: | ||
1048 | case NEWT_KEY_ENTER: | ||
1049 | if (!menu->selection) | ||
1050 | continue; | ||
1051 | pos = menu->selection; | ||
1052 | browse_hists: | ||
1053 | ev_name = event_name(pos); | ||
1054 | key = perf_evsel__hists_browse(pos, help, ev_name, true); | ||
1055 | ui_browser__show_title(&menu->b, title); | ||
1056 | break; | ||
1057 | case NEWT_KEY_LEFT: | ||
1058 | continue; | ||
1059 | case NEWT_KEY_ESCAPE: | ||
1060 | if (!ui__dialog_yesno("Do you really want to exit?")) | ||
1061 | continue; | ||
1062 | /* Fall thru */ | ||
1063 | default: | ||
1064 | goto out; | ||
1065 | } | ||
1001 | 1066 | ||
1002 | switch (key) { | 1067 | switch (key) { |
1003 | case NEWT_KEY_TAB: | 1068 | case NEWT_KEY_TAB: |
@@ -1005,17 +1070,69 @@ int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help) | |||
1005 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | 1070 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); |
1006 | else | 1071 | else |
1007 | pos = list_entry(pos->node.next, struct perf_evsel, node); | 1072 | pos = list_entry(pos->node.next, struct perf_evsel, node); |
1008 | break; | 1073 | goto browse_hists; |
1009 | case NEWT_KEY_UNTAB: | 1074 | case NEWT_KEY_UNTAB: |
1010 | if (pos->node.prev == &evlist->entries) | 1075 | if (pos->node.prev == &evlist->entries) |
1011 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | 1076 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); |
1012 | else | 1077 | else |
1013 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | 1078 | pos = list_entry(pos->node.prev, struct perf_evsel, node); |
1014 | break; | 1079 | goto browse_hists; |
1080 | case 'q': | ||
1081 | case CTRL('c'): | ||
1082 | goto out; | ||
1015 | default: | 1083 | default: |
1016 | return key; | 1084 | break; |
1017 | } | 1085 | } |
1018 | } | 1086 | } |
1019 | 1087 | ||
1020 | return 0; | 1088 | out: |
1089 | ui_browser__hide(&menu->b); | ||
1090 | return key; | ||
1091 | } | ||
1092 | |||
1093 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | ||
1094 | const char *help) | ||
1095 | { | ||
1096 | struct perf_evsel *pos; | ||
1097 | struct perf_evsel_menu menu = { | ||
1098 | .b = { | ||
1099 | .entries = &evlist->entries, | ||
1100 | .refresh = ui_browser__list_head_refresh, | ||
1101 | .seek = ui_browser__list_head_seek, | ||
1102 | .write = perf_evsel_menu__write, | ||
1103 | .nr_entries = evlist->nr_entries, | ||
1104 | .priv = evlist, | ||
1105 | }, | ||
1106 | }; | ||
1107 | |||
1108 | ui_helpline__push("Press ESC to exit"); | ||
1109 | |||
1110 | list_for_each_entry(pos, &evlist->entries, node) { | ||
1111 | const char *ev_name = event_name(pos); | ||
1112 | size_t line_len = strlen(ev_name) + 7; | ||
1113 | |||
1114 | if (menu.b.width < line_len) | ||
1115 | menu.b.width = line_len; | ||
1116 | /* | ||
1117 | * Cache the evsel name, tracepoints have a _high_ cost per | ||
1118 | * event_name() call. | ||
1119 | */ | ||
1120 | if (pos->name == NULL) | ||
1121 | pos->name = strdup(ev_name); | ||
1122 | } | ||
1123 | |||
1124 | return perf_evsel_menu__run(&menu, help); | ||
1125 | } | ||
1126 | |||
1127 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) | ||
1128 | { | ||
1129 | |||
1130 | if (evlist->nr_entries == 1) { | ||
1131 | struct perf_evsel *first = list_entry(evlist->entries.next, | ||
1132 | struct perf_evsel, node); | ||
1133 | const char *ev_name = event_name(first); | ||
1134 | return perf_evsel__hists_browse(first, help, ev_name, false); | ||
1135 | } | ||
1136 | |||
1137 | return __perf_evlist__tui_browse_hists(evlist, help); | ||
1021 | } | 1138 | } |