diff options
Diffstat (limited to 'tools')
-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 | } |