diff options
| -rw-r--r-- | tools/perf/builtin-top.c | 37 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 29 | ||||
| -rw-r--r-- | tools/perf/util/top.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/ui/browser.c | 21 | ||||
| -rw-r--r-- | tools/perf/util/ui/browser.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 49 |
7 files changed, 112 insertions, 29 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31aa82c39e2a..8577bfeb087a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -89,6 +89,7 @@ static bool vmlinux_warned; | |||
| 89 | static bool inherit = false; | 89 | static bool inherit = false; |
| 90 | static int realtime_prio = 0; | 90 | static int realtime_prio = 0; |
| 91 | static bool group = false; | 91 | static bool group = false; |
| 92 | static bool sample_id_all_avail = true; | ||
| 92 | static unsigned int mmap_pages = 128; | 93 | static unsigned int mmap_pages = 128; |
| 93 | 94 | ||
| 94 | static bool dump_symtab = false; | 95 | static bool dump_symtab = false; |
| @@ -289,11 +290,13 @@ static void print_sym_table(void) | |||
| 289 | 290 | ||
| 290 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 291 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
| 291 | 292 | ||
| 292 | if (top.total_lost_warned != top.session->hists.stats.total_lost) { | 293 | if (top.sym_evsel->hists.stats.nr_lost_warned != |
| 293 | top.total_lost_warned = top.session->hists.stats.total_lost; | 294 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { |
| 294 | color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); | 295 | top.sym_evsel->hists.stats.nr_lost_warned = |
| 295 | printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", | 296 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; |
| 296 | top.total_lost_warned); | 297 | color_fprintf(stdout, PERF_COLOR_RED, |
| 298 | "WARNING: LOST %d chunks, Check IO/CPU overload", | ||
| 299 | top.sym_evsel->hists.stats.nr_lost_warned); | ||
| 297 | ++printed; | 300 | ++printed; |
| 298 | } | 301 | } |
| 299 | 302 | ||
| @@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) | |||
| 671 | } | 674 | } |
| 672 | 675 | ||
| 673 | static void perf_event__process_sample(const union perf_event *event, | 676 | static void perf_event__process_sample(const union perf_event *event, |
| 677 | struct perf_evsel *evsel, | ||
| 674 | struct perf_sample *sample, | 678 | struct perf_sample *sample, |
| 675 | struct perf_session *session) | 679 | struct perf_session *session) |
| 676 | { | 680 | { |
| @@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event, | |||
| 770 | } | 774 | } |
| 771 | 775 | ||
| 772 | if (al.sym == NULL || !al.sym->ignore) { | 776 | if (al.sym == NULL || !al.sym->ignore) { |
| 773 | struct perf_evsel *evsel; | ||
| 774 | struct hist_entry *he; | 777 | struct hist_entry *he; |
| 775 | 778 | ||
| 776 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | ||
| 777 | assert(evsel != NULL); | ||
| 778 | |||
| 779 | if ((sort__has_parent || symbol_conf.use_callchain) && | 779 | if ((sort__has_parent || symbol_conf.use_callchain) && |
| 780 | sample->callchain) { | 780 | sample->callchain) { |
| 781 | err = perf_session__resolve_callchain(session, al.thread, | 781 | err = perf_session__resolve_callchain(session, al.thread, |
| @@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
| 807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | 807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) |
| 808 | { | 808 | { |
| 809 | struct perf_sample sample; | 809 | struct perf_sample sample; |
| 810 | struct perf_evsel *evsel; | ||
| 810 | union perf_event *event; | 811 | union perf_event *event; |
| 811 | int ret; | 812 | int ret; |
| 812 | 813 | ||
| @@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | |||
| 817 | continue; | 818 | continue; |
| 818 | } | 819 | } |
| 819 | 820 | ||
| 821 | evsel = perf_evlist__id2evsel(self->evlist, sample.id); | ||
| 822 | assert(evsel != NULL); | ||
| 823 | |||
| 820 | if (event->header.type == PERF_RECORD_SAMPLE) | 824 | if (event->header.type == PERF_RECORD_SAMPLE) |
| 821 | perf_event__process_sample(event, &sample, self); | 825 | perf_event__process_sample(event, evsel, &sample, self); |
| 822 | else | 826 | else if (event->header.type < PERF_RECORD_MAX) { |
| 827 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
| 823 | perf_event__process(event, &sample, self); | 828 | perf_event__process(event, &sample, self); |
| 829 | } else | ||
| 830 | ++self->hists.stats.nr_unknown_events; | ||
| 824 | } | 831 | } |
| 825 | } | 832 | } |
| 826 | 833 | ||
| @@ -864,6 +871,8 @@ static void start_counters(struct perf_evlist *evlist) | |||
| 864 | attr->mmap = 1; | 871 | attr->mmap = 1; |
| 865 | attr->comm = 1; | 872 | attr->comm = 1; |
| 866 | attr->inherit = inherit; | 873 | attr->inherit = inherit; |
| 874 | retry_sample_id: | ||
| 875 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
| 867 | try_again: | 876 | try_again: |
| 868 | if (perf_evsel__open(counter, top.evlist->cpus, | 877 | if (perf_evsel__open(counter, top.evlist->cpus, |
| 869 | top.evlist->threads, group, | 878 | top.evlist->threads, group, |
| @@ -873,6 +882,12 @@ try_again: | |||
| 873 | if (err == EPERM || err == EACCES) { | 882 | if (err == EPERM || err == EACCES) { |
| 874 | ui__error_paranoid(); | 883 | ui__error_paranoid(); |
| 875 | goto out_err; | 884 | goto out_err; |
| 885 | } else if (err == EINVAL && sample_id_all_avail) { | ||
| 886 | /* | ||
| 887 | * Old kernel, no attr->sample_id_type_all field | ||
| 888 | */ | ||
| 889 | sample_id_all_avail = false; | ||
| 890 | goto retry_sample_id; | ||
| 876 | } | 891 | } |
| 877 | /* | 892 | /* |
| 878 | * If it's cycles then fall back to hrtimer | 893 | * If it's cycles then fall back to hrtimer |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff93ddc91c5c..c86c1d27bd1e 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -28,6 +28,7 @@ struct events_stats { | |||
| 28 | u64 total_lost; | 28 | u64 total_lost; |
| 29 | u64 total_invalid_chains; | 29 | u64 total_invalid_chains; |
| 30 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 30 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
| 31 | u32 nr_lost_warned; | ||
| 31 | u32 nr_unknown_events; | 32 | u32 nr_unknown_events; |
| 32 | u32 nr_invalid_chains; | 33 | u32 nr_invalid_chains; |
| 33 | u32 nr_unknown_id; | 34 | u32 nr_unknown_id; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 91c6442ef966..da354fe5e085 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -738,10 +738,27 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 738 | 738 | ||
| 739 | dump_event(session, event, file_offset, sample); | 739 | dump_event(session, event, file_offset, sample); |
| 740 | 740 | ||
| 741 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
| 742 | if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) { | ||
| 743 | /* | ||
| 744 | * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here | ||
| 745 | * because the tools right now may apply filters, discarding | ||
| 746 | * some of the samples. For consistency, in the future we | ||
| 747 | * should have something like nr_filtered_samples and remove | ||
| 748 | * the sample->period from total_sample_period, etc, KISS for | ||
| 749 | * now tho. | ||
| 750 | * | ||
| 751 | * Also testing against NULL allows us to handle files without | ||
| 752 | * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the | ||
| 753 | * future probably it'll be a good idea to restrict event | ||
| 754 | * processing via perf_session to files with both set. | ||
| 755 | */ | ||
| 756 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
| 757 | } | ||
| 758 | |||
| 741 | switch (event->header.type) { | 759 | switch (event->header.type) { |
| 742 | case PERF_RECORD_SAMPLE: | 760 | case PERF_RECORD_SAMPLE: |
| 743 | dump_sample(session, event, sample); | 761 | dump_sample(session, event, sample); |
| 744 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
| 745 | if (evsel == NULL) { | 762 | if (evsel == NULL) { |
| 746 | ++session->hists.stats.nr_unknown_id; | 763 | ++session->hists.stats.nr_unknown_id; |
| 747 | return -1; | 764 | return -1; |
| @@ -874,11 +891,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
| 874 | const struct perf_event_ops *ops) | 891 | const struct perf_event_ops *ops) |
| 875 | { | 892 | { |
| 876 | if (ops->lost == perf_event__process_lost && | 893 | if (ops->lost == perf_event__process_lost && |
| 877 | session->hists.stats.total_lost != 0) { | 894 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { |
| 878 | ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 | 895 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
| 879 | "!\n\nCheck IO/CPU overload!\n\n", | 896 | "Check IO/CPU overload!\n\n", |
| 880 | session->hists.stats.total_period, | 897 | session->hists.stats.nr_events[0], |
| 881 | session->hists.stats.total_lost); | 898 | session->hists.stats.nr_events[PERF_RECORD_LOST]); |
| 882 | } | 899 | } |
| 883 | 900 | ||
| 884 | if (session->hists.stats.nr_unknown_events != 0) { | 901 | if (session->hists.stats.nr_unknown_events != 0) { |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 01d1057f3074..399650967958 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
| @@ -19,7 +19,6 @@ struct perf_top { | |||
| 19 | u64 kernel_samples, us_samples; | 19 | u64 kernel_samples, us_samples; |
| 20 | u64 exact_samples; | 20 | u64 exact_samples; |
| 21 | u64 guest_us_samples, guest_kernel_samples; | 21 | u64 guest_us_samples, guest_kernel_samples; |
| 22 | u64 total_lost_warned; | ||
| 23 | int print_entries, count_filter, delay_secs; | 22 | int print_entries, count_filter, delay_secs; |
| 24 | int freq; | 23 | int freq; |
| 25 | pid_t target_pid, target_tid; | 24 | pid_t target_pid, target_tid; |
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index d2051be04f12..556829124b02 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c | |||
| @@ -176,16 +176,29 @@ void ui_browser__handle_resize(struct ui_browser *browser) | |||
| 176 | ui_browser__refresh(browser); | 176 | ui_browser__refresh(browser); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | int ui_browser__warning(struct ui_browser *browser, const char *format, ...) | 179 | int ui_browser__warning(struct ui_browser *browser, int timeout, |
| 180 | const char *format, ...) | ||
| 180 | { | 181 | { |
| 181 | va_list args; | 182 | va_list args; |
| 182 | int key; | 183 | char *text; |
| 184 | int key = 0, err; | ||
| 183 | 185 | ||
| 184 | va_start(args, format); | 186 | va_start(args, format); |
| 185 | while ((key = __ui__warning("Warning!", format, args)) == K_RESIZE) | 187 | err = vasprintf(&text, format, args); |
| 186 | ui_browser__handle_resize(browser); | ||
| 187 | va_end(args); | 188 | va_end(args); |
| 188 | 189 | ||
| 190 | if (err < 0) { | ||
| 191 | va_start(args, format); | ||
| 192 | ui_helpline__vpush(format, args); | ||
| 193 | va_end(args); | ||
| 194 | } else { | ||
| 195 | while ((key == ui__question_window("Warning!", text, | ||
| 196 | "Press any key...", | ||
| 197 | timeout)) == K_RESIZE) | ||
| 198 | ui_browser__handle_resize(browser); | ||
| 199 | free(text); | ||
| 200 | } | ||
| 201 | |||
| 189 | return key; | 202 | return key; |
| 190 | } | 203 | } |
| 191 | 204 | ||
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index fb1c59883e6a..84d761b730c1 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h | |||
| @@ -45,7 +45,8 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs); | |||
| 45 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); | 45 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); |
| 46 | void ui_browser__handle_resize(struct ui_browser *browser); | 46 | void ui_browser__handle_resize(struct ui_browser *browser); |
| 47 | 47 | ||
| 48 | int ui_browser__warning(struct ui_browser *browser, const char *format, ...); | 48 | int ui_browser__warning(struct ui_browser *browser, int timeout, |
| 49 | const char *format, ...); | ||
| 49 | int ui_browser__help_window(struct ui_browser *browser, const char *text); | 50 | int ui_browser__help_window(struct ui_browser *browser, const char *text); |
| 50 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); | 51 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); |
| 51 | 52 | ||
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index b8733c0770cd..d0c94b459685 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
| @@ -295,6 +295,15 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold) | |||
| 295 | ui_browser__reset_index(&self->b); | 295 | ui_browser__reset_index(&self->b); |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static 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 | |||
| 298 | static int hist_browser__run(struct hist_browser *self, const char *ev_name, | 307 | static int hist_browser__run(struct hist_browser *self, const char *ev_name, |
| 299 | void(*timer)(void *arg), void *arg, int delay_secs) | 308 | void(*timer)(void *arg), void *arg, int delay_secs) |
| 300 | { | 309 | { |
| @@ -318,8 +327,15 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, | |||
| 318 | case K_TIMER: | 327 | case K_TIMER: |
| 319 | timer(arg); | 328 | timer(arg); |
| 320 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); | 329 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); |
| 321 | hists__browser_title(self->hists, title, sizeof(title), | 330 | |
| 322 | ev_name); | 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); | ||
| 323 | ui_browser__show_title(&self->b, title); | 339 | ui_browser__show_title(&self->b, title); |
| 324 | continue; | 340 | continue; |
| 325 | case 'D': { /* Debug */ | 341 | case 'D': { /* Debug */ |
| @@ -883,7 +899,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
| 883 | goto out_free_stack; | 899 | goto out_free_stack; |
| 884 | case 'a': | 900 | case 'a': |
| 885 | if (!browser->has_symbols) { | 901 | if (!browser->has_symbols) { |
| 886 | ui_browser__warning(&browser->b, | 902 | ui_browser__warning(&browser->b, delay_secs * 2, |
| 887 | "Annotation is only available for symbolic views, " | 903 | "Annotation is only available for symbolic views, " |
| 888 | "include \"sym\" in --sort to use it."); | 904 | "include \"sym\" in --sort to use it."); |
| 889 | continue; | 905 | continue; |
| @@ -1061,6 +1077,7 @@ out: | |||
| 1061 | struct perf_evsel_menu { | 1077 | struct perf_evsel_menu { |
| 1062 | struct ui_browser b; | 1078 | struct ui_browser b; |
| 1063 | struct perf_evsel *selection; | 1079 | struct perf_evsel *selection; |
| 1080 | bool lost_events, lost_events_warned; | ||
| 1064 | }; | 1081 | }; |
| 1065 | 1082 | ||
| 1066 | static void perf_evsel_menu__write(struct ui_browser *browser, | 1083 | static void perf_evsel_menu__write(struct ui_browser *browser, |
| @@ -1073,14 +1090,29 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
| 1073 | 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]; |
| 1074 | const char *ev_name = event_name(evsel); | 1091 | const char *ev_name = event_name(evsel); |
| 1075 | char bf[256], unit; | 1092 | char bf[256], unit; |
| 1093 | const char *warn = " "; | ||
| 1094 | size_t printed; | ||
| 1076 | 1095 | ||
| 1077 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1096 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
| 1078 | HE_COLORSET_NORMAL); | 1097 | HE_COLORSET_NORMAL); |
| 1079 | 1098 | ||
| 1080 | nr_events = convert_unit(nr_events, &unit); | 1099 | nr_events = convert_unit(nr_events, &unit); |
| 1081 | snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | 1100 | printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, |
| 1082 | unit, unit == ' ' ? "" : " ", ev_name); | 1101 | unit, unit == ' ' ? "" : " ", ev_name); |
| 1083 | 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); | ||
| 1084 | 1116 | ||
| 1085 | if (current_entry) | 1117 | if (current_entry) |
| 1086 | menu->selection = evsel; | 1118 | menu->selection = evsel; |
| @@ -1105,6 +1137,11 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, | |||
| 1105 | switch (key) { | 1137 | switch (key) { |
| 1106 | case K_TIMER: | 1138 | case K_TIMER: |
| 1107 | timer(arg); | 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 | } | ||
| 1108 | continue; | 1145 | continue; |
| 1109 | case K_RIGHT: | 1146 | case K_RIGHT: |
| 1110 | case K_ENTER: | 1147 | case K_ENTER: |
