aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ui/browsers/hists.c')
-rw-r--r--tools/perf/util/ui/browsers/hists.c351
1 files changed, 237 insertions, 114 deletions
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 5d767c622dfc..1212a386a033 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -17,6 +17,7 @@
17#include "../browser.h" 17#include "../browser.h"
18#include "../helpline.h" 18#include "../helpline.h"
19#include "../util.h" 19#include "../util.h"
20#include "../ui.h"
20#include "map.h" 21#include "map.h"
21 22
22struct hist_browser { 23struct hist_browser {
@@ -24,8 +25,12 @@ struct hist_browser {
24 struct hists *hists; 25 struct hists *hists;
25 struct hist_entry *he_selection; 26 struct hist_entry *he_selection;
26 struct map_symbol *selection; 27 struct map_symbol *selection;
28 bool has_symbols;
27}; 29};
28 30
31static int hists__browser_title(struct hists *self, char *bf, size_t size,
32 const char *ev_name);
33
29static void hist_browser__refresh_dimensions(struct hist_browser *self) 34static void hist_browser__refresh_dimensions(struct hist_browser *self)
30{ 35{
31 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 36 /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,28 +295,49 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
290 ui_browser__reset_index(&self->b); 295 ui_browser__reset_index(&self->b);
291} 296}
292 297
293static int hist_browser__run(struct hist_browser *self, const char *title) 298static void ui_browser__warn_lost_events(struct ui_browser *browser)
299{
300 ui_browser__warning(browser, 4,
301 "Events are being lost, check IO/CPU overload!\n\n"
302 "You may want to run 'perf' using a RT scheduler policy:\n\n"
303 " perf top -r 80\n\n"
304 "Or reduce the sampling frequency.");
305}
306
307static int hist_browser__run(struct hist_browser *self, const char *ev_name,
308 void(*timer)(void *arg), void *arg, int delay_secs)
294{ 309{
295 int key; 310 int key;
296 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', 311 char title[160];
297 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
298 NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
299 312
300 self->b.entries = &self->hists->entries; 313 self->b.entries = &self->hists->entries;
301 self->b.nr_entries = self->hists->nr_entries; 314 self->b.nr_entries = self->hists->nr_entries;
302 315
303 hist_browser__refresh_dimensions(self); 316 hist_browser__refresh_dimensions(self);
317 hists__browser_title(self->hists, title, sizeof(title), ev_name);
304 318
305 if (ui_browser__show(&self->b, title, 319 if (ui_browser__show(&self->b, title,
306 "Press '?' for help on key bindings") < 0) 320 "Press '?' for help on key bindings") < 0)
307 return -1; 321 return -1;
308 322
309 ui_browser__add_exit_keys(&self->b, exit_keys);
310
311 while (1) { 323 while (1) {
312 key = ui_browser__run(&self->b); 324 key = ui_browser__run(&self->b, delay_secs);
313 325
314 switch (key) { 326 switch (key) {
327 case K_TIMER:
328 timer(arg);
329 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
330
331 if (self->hists->stats.nr_lost_warned !=
332 self->hists->stats.nr_events[PERF_RECORD_LOST]) {
333 self->hists->stats.nr_lost_warned =
334 self->hists->stats.nr_events[PERF_RECORD_LOST];
335 ui_browser__warn_lost_events(&self->b);
336 }
337
338 hists__browser_title(self->hists, title, sizeof(title), ev_name);
339 ui_browser__show_title(&self->b, title);
340 continue;
315 case 'D': { /* Debug */ 341 case 'D': { /* Debug */
316 static int seq; 342 static int seq;
317 struct hist_entry *h = rb_entry(self->b.top, 343 struct hist_entry *h = rb_entry(self->b.top,
@@ -334,7 +360,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
334 /* Expand the whole world. */ 360 /* Expand the whole world. */
335 hist_browser__set_folding(self, true); 361 hist_browser__set_folding(self, true);
336 break; 362 break;
337 case NEWT_KEY_ENTER: 363 case K_ENTER:
338 if (hist_browser__toggle_fold(self)) 364 if (hist_browser__toggle_fold(self))
339 break; 365 break;
340 /* fall thru */ 366 /* fall thru */
@@ -532,7 +558,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
532 char s[256]; 558 char s[256];
533 double percent; 559 double percent;
534 int printed = 0; 560 int printed = 0;
535 int color, width = self->b.width; 561 int width = self->b.width - 6; /* The percentage */
536 char folded_sign = ' '; 562 char folded_sign = ' ';
537 bool current_entry = ui_browser__is_current_entry(&self->b, row); 563 bool current_entry = ui_browser__is_current_entry(&self->b, row);
538 off_t row_offset = entry->row_offset; 564 off_t row_offset = entry->row_offset;
@@ -548,26 +574,35 @@ static int hist_browser__show_entry(struct hist_browser *self,
548 } 574 }
549 575
550 if (row_offset == 0) { 576 if (row_offset == 0) {
551 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, 577 hist_entry__snprintf(entry, s, sizeof(s), self->hists);
552 0, false, self->hists->stats.total_period);
553 percent = (entry->period * 100.0) / self->hists->stats.total_period; 578 percent = (entry->period * 100.0) / self->hists->stats.total_period;
554 579
555 color = HE_COLORSET_SELECTED; 580 ui_browser__set_percent_color(&self->b, percent, current_entry);
556 if (!current_entry) {
557 if (percent >= MIN_RED)
558 color = HE_COLORSET_TOP;
559 else if (percent >= MIN_GREEN)
560 color = HE_COLORSET_MEDIUM;
561 else
562 color = HE_COLORSET_NORMAL;
563 }
564
565 ui_browser__set_color(&self->b, color);
566 ui_browser__gotorc(&self->b, row, 0); 581 ui_browser__gotorc(&self->b, row, 0);
567 if (symbol_conf.use_callchain) { 582 if (symbol_conf.use_callchain) {
568 slsmg_printf("%c ", folded_sign); 583 slsmg_printf("%c ", folded_sign);
569 width -= 2; 584 width -= 2;
570 } 585 }
586
587 slsmg_printf(" %5.2f%%", percent);
588
589 /* The scroll bar isn't being used */
590 if (!self->b.navkeypressed)
591 width += 1;
592
593 if (!current_entry || !self->b.navkeypressed)
594 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
595
596 if (symbol_conf.show_nr_samples) {
597 slsmg_printf(" %11u", entry->nr_events);
598 width -= 12;
599 }
600
601 if (symbol_conf.show_total_period) {
602 slsmg_printf(" %12" PRIu64, entry->period);
603 width -= 13;
604 }
605
571 slsmg_write_nstring(s, width); 606 slsmg_write_nstring(s, width);
572 ++row; 607 ++row;
573 ++printed; 608 ++printed;
@@ -585,14 +620,23 @@ static int hist_browser__show_entry(struct hist_browser *self,
585 return printed; 620 return printed;
586} 621}
587 622
623static void ui_browser__hists_init_top(struct ui_browser *browser)
624{
625 if (browser->top == NULL) {
626 struct hist_browser *hb;
627
628 hb = container_of(browser, struct hist_browser, b);
629 browser->top = rb_first(&hb->hists->entries);
630 }
631}
632
588static unsigned int hist_browser__refresh(struct ui_browser *self) 633static unsigned int hist_browser__refresh(struct ui_browser *self)
589{ 634{
590 unsigned row = 0; 635 unsigned row = 0;
591 struct rb_node *nd; 636 struct rb_node *nd;
592 struct hist_browser *hb = container_of(self, struct hist_browser, b); 637 struct hist_browser *hb = container_of(self, struct hist_browser, b);
593 638
594 if (self->top == NULL) 639 ui_browser__hists_init_top(self);
595 self->top = rb_first(&hb->hists->entries);
596 640
597 for (nd = self->top; nd; nd = rb_next(nd)) { 641 for (nd = self->top; nd; nd = rb_next(nd)) {
598 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 642 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -644,6 +688,8 @@ static void ui_browser__hists_seek(struct ui_browser *self,
644 if (self->nr_entries == 0) 688 if (self->nr_entries == 0)
645 return; 689 return;
646 690
691 ui_browser__hists_init_top(self);
692
647 switch (whence) { 693 switch (whence) {
648 case SEEK_SET: 694 case SEEK_SET:
649 nd = hists__filter_entries(rb_first(self->entries)); 695 nd = hists__filter_entries(rb_first(self->entries));
@@ -761,6 +807,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
761 self->hists = hists; 807 self->hists = hists;
762 self->b.refresh = hist_browser__refresh; 808 self->b.refresh = hist_browser__refresh;
763 self->b.seek = ui_browser__hists_seek; 809 self->b.seek = ui_browser__hists_seek;
810 self->b.use_navkeypressed = true,
811 self->has_symbols = sort_sym.list.next != NULL;
764 } 812 }
765 813
766 return self; 814 return self;
@@ -782,11 +830,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
782} 830}
783 831
784static int hists__browser_title(struct hists *self, char *bf, size_t size, 832static int hists__browser_title(struct hists *self, char *bf, size_t size,
785 const char *ev_name, const struct dso *dso, 833 const char *ev_name)
786 const struct thread *thread)
787{ 834{
788 char unit; 835 char unit;
789 int printed; 836 int printed;
837 const struct dso *dso = self->dso_filter;
838 const struct thread *thread = self->thread_filter;
790 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 839 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
791 840
792 nr_events = convert_unit(nr_events, &unit); 841 nr_events = convert_unit(nr_events, &unit);
@@ -803,16 +852,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
803 return printed; 852 return printed;
804} 853}
805 854
806static int perf_evsel__hists_browse(struct perf_evsel *evsel, 855static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
807 const char *helpline, const char *ev_name, 856 const char *helpline, const char *ev_name,
808 bool left_exits) 857 bool left_exits,
858 void(*timer)(void *arg), void *arg,
859 int delay_secs)
809{ 860{
810 struct hists *self = &evsel->hists; 861 struct hists *self = &evsel->hists;
811 struct hist_browser *browser = hist_browser__new(self); 862 struct hist_browser *browser = hist_browser__new(self);
812 struct pstack *fstack; 863 struct pstack *fstack;
813 const struct thread *thread_filter = NULL;
814 const struct dso *dso_filter = NULL;
815 char msg[160];
816 int key = -1; 864 int key = -1;
817 865
818 if (browser == NULL) 866 if (browser == NULL)
@@ -824,8 +872,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
824 872
825 ui_helpline__push(helpline); 873 ui_helpline__push(helpline);
826 874
827 hists__browser_title(self, msg, sizeof(msg), ev_name,
828 dso_filter, thread_filter);
829 while (1) { 875 while (1) {
830 const struct thread *thread = NULL; 876 const struct thread *thread = NULL;
831 const struct dso *dso = NULL; 877 const struct dso *dso = NULL;
@@ -834,7 +880,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
834 annotate = -2, zoom_dso = -2, zoom_thread = -2, 880 annotate = -2, zoom_dso = -2, zoom_thread = -2,
835 browse_map = -2; 881 browse_map = -2;
836 882
837 key = hist_browser__run(browser, msg); 883 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
838 884
839 if (browser->he_selection != NULL) { 885 if (browser->he_selection != NULL) {
840 thread = hist_browser__selected_thread(browser); 886 thread = hist_browser__selected_thread(browser);
@@ -842,14 +888,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
842 } 888 }
843 889
844 switch (key) { 890 switch (key) {
845 case NEWT_KEY_TAB: 891 case K_TAB:
846 case NEWT_KEY_UNTAB: 892 case K_UNTAB:
893 if (nr_events == 1)
894 continue;
847 /* 895 /*
848 * Exit the browser, let hists__browser_tree 896 * Exit the browser, let hists__browser_tree
849 * go to the next or previous 897 * go to the next or previous
850 */ 898 */
851 goto out_free_stack; 899 goto out_free_stack;
852 case 'a': 900 case 'a':
901 if (!browser->has_symbols) {
902 ui_browser__warning(&browser->b, delay_secs * 2,
903 "Annotation is only available for symbolic views, "
904 "include \"sym\" in --sort to use it.");
905 continue;
906 }
907
853 if (browser->selection == NULL || 908 if (browser->selection == NULL ||
854 browser->selection->sym == NULL || 909 browser->selection->sym == NULL ||
855 browser->selection->map->dso->annotate_warned) 910 browser->selection->map->dso->annotate_warned)
@@ -859,25 +914,30 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
859 goto zoom_dso; 914 goto zoom_dso;
860 case 't': 915 case 't':
861 goto zoom_thread; 916 goto zoom_thread;
862 case NEWT_KEY_F1: 917 case K_F1:
863 case 'h': 918 case 'h':
864 case '?': 919 case '?':
865 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" 920 ui_browser__help_window(&browser->b,
866 "<- Zoom out\n" 921 "h/?/F1 Show this window\n"
867 "a Annotate current symbol\n" 922 "UP/DOWN/PGUP\n"
868 "h/?/F1 Show this window\n" 923 "PGDN/SPACE Navigate\n"
869 "C Collapse all callchains\n" 924 "q/ESC/CTRL+C Exit browser\n\n"
870 "E Expand all callchains\n" 925 "For multiple event sessions:\n\n"
871 "d Zoom into current DSO\n" 926 "TAB/UNTAB Switch events\n\n"
872 "t Zoom into current Thread\n" 927 "For symbolic views (--sort has sym):\n\n"
873 "TAB/UNTAB Switch events\n" 928 "-> Zoom into DSO/Threads & Annotate current symbol\n"
874 "q/CTRL+C Exit browser"); 929 "<- Zoom out\n"
930 "a Annotate current symbol\n"
931 "C Collapse all callchains\n"
932 "E Expand all callchains\n"
933 "d Zoom into current DSO\n"
934 "t Zoom into current Thread");
875 continue; 935 continue;
876 case NEWT_KEY_ENTER: 936 case K_ENTER:
877 case NEWT_KEY_RIGHT: 937 case K_RIGHT:
878 /* menu */ 938 /* menu */
879 break; 939 break;
880 case NEWT_KEY_LEFT: { 940 case K_LEFT: {
881 const void *top; 941 const void *top;
882 942
883 if (pstack__empty(fstack)) { 943 if (pstack__empty(fstack)) {
@@ -889,21 +949,28 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
889 continue; 949 continue;
890 } 950 }
891 top = pstack__pop(fstack); 951 top = pstack__pop(fstack);
892 if (top == &dso_filter) 952 if (top == &browser->hists->dso_filter)
893 goto zoom_out_dso; 953 goto zoom_out_dso;
894 if (top == &thread_filter) 954 if (top == &browser->hists->thread_filter)
895 goto zoom_out_thread; 955 goto zoom_out_thread;
896 continue; 956 continue;
897 } 957 }
898 case NEWT_KEY_ESCAPE: 958 case K_ESC:
899 if (!left_exits && 959 if (!left_exits &&
900 !ui__dialog_yesno("Do you really want to exit?")) 960 !ui_browser__dialog_yesno(&browser->b,
961 "Do you really want to exit?"))
901 continue; 962 continue;
902 /* Fall thru */ 963 /* Fall thru */
903 default: 964 case 'q':
965 case CTRL('c'):
904 goto out_free_stack; 966 goto out_free_stack;
967 default:
968 continue;
905 } 969 }
906 970
971 if (!browser->has_symbols)
972 goto add_exit_option;
973
907 if (browser->selection != NULL && 974 if (browser->selection != NULL &&
908 browser->selection->sym != NULL && 975 browser->selection->sym != NULL &&
909 !browser->selection->map->dso->annotate_warned && 976 !browser->selection->map->dso->annotate_warned &&
@@ -913,14 +980,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
913 980
914 if (thread != NULL && 981 if (thread != NULL &&
915 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 982 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
916 (thread_filter ? "out of" : "into"), 983 (browser->hists->thread_filter ? "out of" : "into"),
917 (thread->comm_set ? thread->comm : ""), 984 (thread->comm_set ? thread->comm : ""),
918 thread->pid) > 0) 985 thread->pid) > 0)
919 zoom_thread = nr_options++; 986 zoom_thread = nr_options++;
920 987
921 if (dso != NULL && 988 if (dso != NULL &&
922 asprintf(&options[nr_options], "Zoom %s %s DSO", 989 asprintf(&options[nr_options], "Zoom %s %s DSO",
923 (dso_filter ? "out of" : "into"), 990 (browser->hists->dso_filter ? "out of" : "into"),
924 (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 991 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
925 zoom_dso = nr_options++; 992 zoom_dso = nr_options++;
926 993
@@ -928,7 +995,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
928 browser->selection->map != NULL && 995 browser->selection->map != NULL &&
929 asprintf(&options[nr_options], "Browse map details") > 0) 996 asprintf(&options[nr_options], "Browse map details") > 0)
930 browse_map = nr_options++; 997 browse_map = nr_options++;
931 998add_exit_option:
932 options[nr_options++] = (char *)"Exit"; 999 options[nr_options++] = (char *)"Exit";
933 1000
934 choice = ui__popup_menu(nr_options, options); 1001 choice = ui__popup_menu(nr_options, options);
@@ -944,50 +1011,59 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
944 1011
945 if (choice == annotate) { 1012 if (choice == annotate) {
946 struct hist_entry *he; 1013 struct hist_entry *he;
1014 int err;
947do_annotate: 1015do_annotate:
948 he = hist_browser__selected_entry(browser); 1016 he = hist_browser__selected_entry(browser);
949 if (he == NULL) 1017 if (he == NULL)
950 continue; 1018 continue;
951 1019 /*
952 hist_entry__tui_annotate(he, evsel->idx); 1020 * Don't let this be freed, say, by hists__decay_entry.
1021 */
1022 he->used = true;
1023 err = hist_entry__tui_annotate(he, evsel->idx,
1024 timer, arg, delay_secs);
1025 he->used = false;
1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1027 if (err)
1028 ui_browser__handle_resize(&browser->b);
953 } else if (choice == browse_map) 1029 } else if (choice == browse_map)
954 map__browse(browser->selection->map); 1030 map__browse(browser->selection->map);
955 else if (choice == zoom_dso) { 1031 else if (choice == zoom_dso) {
956zoom_dso: 1032zoom_dso:
957 if (dso_filter) { 1033 if (browser->hists->dso_filter) {
958 pstack__remove(fstack, &dso_filter); 1034 pstack__remove(fstack, &browser->hists->dso_filter);
959zoom_out_dso: 1035zoom_out_dso:
960 ui_helpline__pop(); 1036 ui_helpline__pop();
961 dso_filter = NULL; 1037 browser->hists->dso_filter = NULL;
1038 sort_dso.elide = false;
962 } else { 1039 } else {
963 if (dso == NULL) 1040 if (dso == NULL)
964 continue; 1041 continue;
965 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1042 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
966 dso->kernel ? "the Kernel" : dso->short_name); 1043 dso->kernel ? "the Kernel" : dso->short_name);
967 dso_filter = dso; 1044 browser->hists->dso_filter = dso;
968 pstack__push(fstack, &dso_filter); 1045 sort_dso.elide = true;
1046 pstack__push(fstack, &browser->hists->dso_filter);
969 } 1047 }
970 hists__filter_by_dso(self, dso_filter); 1048 hists__filter_by_dso(self);
971 hists__browser_title(self, msg, sizeof(msg), ev_name,
972 dso_filter, thread_filter);
973 hist_browser__reset(browser); 1049 hist_browser__reset(browser);
974 } else if (choice == zoom_thread) { 1050 } else if (choice == zoom_thread) {
975zoom_thread: 1051zoom_thread:
976 if (thread_filter) { 1052 if (browser->hists->thread_filter) {
977 pstack__remove(fstack, &thread_filter); 1053 pstack__remove(fstack, &browser->hists->thread_filter);
978zoom_out_thread: 1054zoom_out_thread:
979 ui_helpline__pop(); 1055 ui_helpline__pop();
980 thread_filter = NULL; 1056 browser->hists->thread_filter = NULL;
1057 sort_thread.elide = false;
981 } else { 1058 } else {
982 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1059 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
983 thread->comm_set ? thread->comm : "", 1060 thread->comm_set ? thread->comm : "",
984 thread->pid); 1061 thread->pid);
985 thread_filter = thread; 1062 browser->hists->thread_filter = thread;
986 pstack__push(fstack, &thread_filter); 1063 sort_thread.elide = true;
1064 pstack__push(fstack, &browser->hists->thread_filter);
987 } 1065 }
988 hists__filter_by_thread(self, thread_filter); 1066 hists__filter_by_thread(self);
989 hists__browser_title(self, msg, sizeof(msg), ev_name,
990 dso_filter, thread_filter);
991 hist_browser__reset(browser); 1067 hist_browser__reset(browser);
992 } 1068 }
993 } 1069 }
@@ -1001,6 +1077,7 @@ out:
1001struct perf_evsel_menu { 1077struct perf_evsel_menu {
1002 struct ui_browser b; 1078 struct ui_browser b;
1003 struct perf_evsel *selection; 1079 struct perf_evsel *selection;
1080 bool lost_events, lost_events_warned;
1004}; 1081};
1005 1082
1006static void perf_evsel_menu__write(struct ui_browser *browser, 1083static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1013,22 +1090,38 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1013 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1090 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1014 const char *ev_name = event_name(evsel); 1091 const char *ev_name = event_name(evsel);
1015 char bf[256], unit; 1092 char bf[256], unit;
1093 const char *warn = " ";
1094 size_t printed;
1016 1095
1017 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1096 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1018 HE_COLORSET_NORMAL); 1097 HE_COLORSET_NORMAL);
1019 1098
1020 nr_events = convert_unit(nr_events, &unit); 1099 nr_events = convert_unit(nr_events, &unit);
1021 snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1100 printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1022 unit, unit == ' ' ? "" : " ", ev_name); 1101 unit, unit == ' ' ? "" : " ", ev_name);
1023 slsmg_write_nstring(bf, browser->width); 1102 slsmg_printf("%s", bf);
1103
1104 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1105 if (nr_events != 0) {
1106 menu->lost_events = true;
1107 if (!current_entry)
1108 ui_browser__set_color(browser, HE_COLORSET_TOP);
1109 nr_events = convert_unit(nr_events, &unit);
1110 snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events,
1111 unit, unit == ' ' ? "" : " ");
1112 warn = bf;
1113 }
1114
1115 slsmg_write_nstring(warn, browser->width - printed);
1024 1116
1025 if (current_entry) 1117 if (current_entry)
1026 menu->selection = evsel; 1118 menu->selection = evsel;
1027} 1119}
1028 1120
1029static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) 1121static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1122 int nr_events, const char *help,
1123 void(*timer)(void *arg), void *arg, int delay_secs)
1030{ 1124{
1031 int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
1032 struct perf_evlist *evlist = menu->b.priv; 1125 struct perf_evlist *evlist = menu->b.priv;
1033 struct perf_evsel *pos; 1126 struct perf_evsel *pos;
1034 const char *ev_name, *title = "Available samples"; 1127 const char *ev_name, *title = "Available samples";
@@ -1038,50 +1131,72 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
1038 "ESC: exit, ENTER|->: Browse histograms") < 0) 1131 "ESC: exit, ENTER|->: Browse histograms") < 0)
1039 return -1; 1132 return -1;
1040 1133
1041 ui_browser__add_exit_keys(&menu->b, exit_keys);
1042
1043 while (1) { 1134 while (1) {
1044 key = ui_browser__run(&menu->b); 1135 key = ui_browser__run(&menu->b, delay_secs);
1045 1136
1046 switch (key) { 1137 switch (key) {
1047 case NEWT_KEY_RIGHT: 1138 case K_TIMER:
1048 case NEWT_KEY_ENTER: 1139 timer(arg);
1140
1141 if (!menu->lost_events_warned && menu->lost_events) {
1142 ui_browser__warn_lost_events(&menu->b);
1143 menu->lost_events_warned = true;
1144 }
1145 continue;
1146 case K_RIGHT:
1147 case K_ENTER:
1049 if (!menu->selection) 1148 if (!menu->selection)
1050 continue; 1149 continue;
1051 pos = menu->selection; 1150 pos = menu->selection;
1052browse_hists: 1151browse_hists:
1152 perf_evlist__set_selected(evlist, pos);
1153 /*
1154 * Give the calling tool a chance to populate the non
1155 * default evsel resorted hists tree.
1156 */
1157 if (timer)
1158 timer(arg);
1053 ev_name = event_name(pos); 1159 ev_name = event_name(pos);
1054 key = perf_evsel__hists_browse(pos, help, ev_name, true); 1160 key = perf_evsel__hists_browse(pos, nr_events, help,
1161 ev_name, true, timer,
1162 arg, delay_secs);
1055 ui_browser__show_title(&menu->b, title); 1163 ui_browser__show_title(&menu->b, title);
1056 break; 1164 switch (key) {
1057 case NEWT_KEY_LEFT: 1165 case K_TAB:
1166 if (pos->node.next == &evlist->entries)
1167 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1168 else
1169 pos = list_entry(pos->node.next, struct perf_evsel, node);
1170 goto browse_hists;
1171 case K_UNTAB:
1172 if (pos->node.prev == &evlist->entries)
1173 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1174 else
1175 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1176 goto browse_hists;
1177 case K_ESC:
1178 if (!ui_browser__dialog_yesno(&menu->b,
1179 "Do you really want to exit?"))
1180 continue;
1181 /* Fall thru */
1182 case 'q':
1183 case CTRL('c'):
1184 goto out;
1185 default:
1186 continue;
1187 }
1188 case K_LEFT:
1058 continue; 1189 continue;
1059 case NEWT_KEY_ESCAPE: 1190 case K_ESC:
1060 if (!ui__dialog_yesno("Do you really want to exit?")) 1191 if (!ui_browser__dialog_yesno(&menu->b,
1192 "Do you really want to exit?"))
1061 continue; 1193 continue;
1062 /* Fall thru */ 1194 /* Fall thru */
1063 default:
1064 goto out;
1065 }
1066
1067 switch (key) {
1068 case NEWT_KEY_TAB:
1069 if (pos->node.next == &evlist->entries)
1070 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1071 else
1072 pos = list_entry(pos->node.next, struct perf_evsel, node);
1073 goto browse_hists;
1074 case NEWT_KEY_UNTAB:
1075 if (pos->node.prev == &evlist->entries)
1076 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1077 else
1078 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1079 goto browse_hists;
1080 case 'q': 1195 case 'q':
1081 case CTRL('c'): 1196 case CTRL('c'):
1082 goto out; 1197 goto out;
1083 default: 1198 default:
1084 break; 1199 continue;
1085 } 1200 }
1086 } 1201 }
1087 1202
@@ -1091,7 +1206,9 @@ out:
1091} 1206}
1092 1207
1093static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1208static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1094 const char *help) 1209 const char *help,
1210 void(*timer)(void *arg), void *arg,
1211 int delay_secs)
1095{ 1212{
1096 struct perf_evsel *pos; 1213 struct perf_evsel *pos;
1097 struct perf_evsel_menu menu = { 1214 struct perf_evsel_menu menu = {
@@ -1121,18 +1238,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1121 pos->name = strdup(ev_name); 1238 pos->name = strdup(ev_name);
1122 } 1239 }
1123 1240
1124 return perf_evsel_menu__run(&menu, help); 1241 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1242 arg, delay_secs);
1125} 1243}
1126 1244
1127int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) 1245int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1246 void(*timer)(void *arg), void *arg,
1247 int delay_secs)
1128{ 1248{
1129 1249
1130 if (evlist->nr_entries == 1) { 1250 if (evlist->nr_entries == 1) {
1131 struct perf_evsel *first = list_entry(evlist->entries.next, 1251 struct perf_evsel *first = list_entry(evlist->entries.next,
1132 struct perf_evsel, node); 1252 struct perf_evsel, node);
1133 const char *ev_name = event_name(first); 1253 const char *ev_name = event_name(first);
1134 return perf_evsel__hists_browse(first, help, ev_name, false); 1254 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1255 ev_name, false, timer, arg,
1256 delay_secs);
1135 } 1257 }
1136 1258
1137 return __perf_evlist__tui_browse_hists(evlist, help); 1259 return __perf_evlist__tui_browse_hists(evlist, help,
1260 timer, arg, delay_secs);
1138} 1261}