Skip to content

Commit 7b27509

Browse files
committed
perf hists browser: Warn about lost events
Just like the old perf top --tui and the --stdio version. But because we have the initial menu to choose which event to show in a session with multiple events we can see how many chunks were lost in each of the event types, clarifying which events are being affected the most. Cc: David Ahern <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Link: http://lkml.kernel.org/n/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 1ca4ff4 commit 7b27509

File tree

7 files changed

+112
-29
lines changed

7 files changed

+112
-29
lines changed

tools/perf/builtin-top.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static bool vmlinux_warned;
8989
static bool inherit = false;
9090
static int realtime_prio = 0;
9191
static bool group = false;
92+
static bool sample_id_all_avail = true;
9293
static unsigned int mmap_pages = 128;
9394

9495
static bool dump_symtab = false;
@@ -289,11 +290,13 @@ static void print_sym_table(void)
289290

290291
printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
291292

292-
if (top.total_lost_warned != top.session->hists.stats.total_lost) {
293-
top.total_lost_warned = top.session->hists.stats.total_lost;
294-
color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
295-
printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
296-
top.total_lost_warned);
293+
if (top.sym_evsel->hists.stats.nr_lost_warned !=
294+
top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
295+
top.sym_evsel->hists.stats.nr_lost_warned =
296+
top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
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);
297300
++printed;
298301
}
299302

@@ -671,6 +674,7 @@ static int symbol_filter(struct map *map __used, struct symbol *sym)
671674
}
672675

673676
static void perf_event__process_sample(const union perf_event *event,
677+
struct perf_evsel *evsel,
674678
struct perf_sample *sample,
675679
struct perf_session *session)
676680
{
@@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event,
770774
}
771775

772776
if (al.sym == NULL || !al.sym->ignore) {
773-
struct perf_evsel *evsel;
774777
struct hist_entry *he;
775778

776-
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
777-
assert(evsel != NULL);
778-
779779
if ((sort__has_parent || symbol_conf.use_callchain) &&
780780
sample->callchain) {
781781
err = perf_session__resolve_callchain(session, al.thread,
@@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event,
807807
static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
808808
{
809809
struct perf_sample sample;
810+
struct perf_evsel *evsel;
810811
union perf_event *event;
811812
int ret;
812813

@@ -817,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
817818
continue;
818819
}
819820

821+
evsel = perf_evlist__id2evsel(self->evlist, sample.id);
822+
assert(evsel != NULL);
823+
820824
if (event->header.type == PERF_RECORD_SAMPLE)
821-
perf_event__process_sample(event, &sample, self);
822-
else
825+
perf_event__process_sample(event, evsel, &sample, self);
826+
else if (event->header.type < PERF_RECORD_MAX) {
827+
hists__inc_nr_events(&evsel->hists, event->header.type);
823828
perf_event__process(event, &sample, self);
829+
} else
830+
++self->hists.stats.nr_unknown_events;
824831
}
825832
}
826833

@@ -864,6 +871,8 @@ static void start_counters(struct perf_evlist *evlist)
864871
attr->mmap = 1;
865872
attr->comm = 1;
866873
attr->inherit = inherit;
874+
retry_sample_id:
875+
attr->sample_id_all = sample_id_all_avail ? 1 : 0;
867876
try_again:
868877
if (perf_evsel__open(counter, top.evlist->cpus,
869878
top.evlist->threads, group,
@@ -873,6 +882,12 @@ static void start_counters(struct perf_evlist *evlist)
873882
if (err == EPERM || err == EACCES) {
874883
ui__error_paranoid();
875884
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;
876891
}
877892
/*
878893
* If it's cycles then fall back to hrtimer

tools/perf/util/hist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct events_stats {
2828
u64 total_lost;
2929
u64 total_invalid_chains;
3030
u32 nr_events[PERF_RECORD_HEADER_MAX];
31+
u32 nr_lost_warned;
3132
u32 nr_unknown_events;
3233
u32 nr_invalid_chains;
3334
u32 nr_unknown_id;

tools/perf/util/session.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -738,10 +738,27 @@ static int perf_session_deliver_event(struct perf_session *session,
738738

739739
dump_event(session, event, file_offset, sample);
740740

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+
741759
switch (event->header.type) {
742760
case PERF_RECORD_SAMPLE:
743761
dump_sample(session, event, sample);
744-
evsel = perf_evlist__id2evsel(session->evlist, sample->id);
745762
if (evsel == NULL) {
746763
++session->hists.stats.nr_unknown_id;
747764
return -1;
@@ -874,11 +891,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
874891
const struct perf_event_ops *ops)
875892
{
876893
if (ops->lost == perf_event__process_lost &&
877-
session->hists.stats.total_lost != 0) {
878-
ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
879-
"!\n\nCheck IO/CPU overload!\n\n",
880-
session->hists.stats.total_period,
881-
session->hists.stats.total_lost);
894+
session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
895+
ui__warning("Processed %d events and lost %d chunks!\n\n"
896+
"Check IO/CPU overload!\n\n",
897+
session->hists.stats.nr_events[0],
898+
session->hists.stats.nr_events[PERF_RECORD_LOST]);
882899
}
883900

884901
if (session->hists.stats.nr_unknown_events != 0) {

tools/perf/util/top.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ struct perf_top {
1919
u64 kernel_samples, us_samples;
2020
u64 exact_samples;
2121
u64 guest_us_samples, guest_kernel_samples;
22-
u64 total_lost_warned;
2322
int print_entries, count_filter, delay_secs;
2423
int freq;
2524
pid_t target_pid, target_tid;

tools/perf/util/ui/browser.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,29 @@ void ui_browser__handle_resize(struct ui_browser *browser)
176176
ui_browser__refresh(browser);
177177
}
178178

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, ...)
180181
{
181182
va_list args;
182-
int key;
183+
char *text;
184+
int key = 0, err;
183185

184186
va_start(args, format);
185-
while ((key = __ui__warning("Warning!", format, args)) == K_RESIZE)
186-
ui_browser__handle_resize(browser);
187+
err = vasprintf(&text, format, args);
187188
va_end(args);
188189

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+
189202
return key;
190203
}
191204

tools/perf/util/ui/browser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs);
4545
void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
4646
void ui_browser__handle_resize(struct ui_browser *browser);
4747

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, ...);
4950
int ui_browser__help_window(struct ui_browser *browser, const char *text);
5051
bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
5152

tools/perf/util/ui/browsers/hists.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,15 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
295295
ui_browser__reset_index(&self->b);
296296
}
297297

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+
298307
static int hist_browser__run(struct hist_browser *self, const char *ev_name,
299308
void(*timer)(void *arg), void *arg, int delay_secs)
300309
{
@@ -318,8 +327,15 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name,
318327
case K_TIMER:
319328
timer(arg);
320329
ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
321-
hists__browser_title(self->hists, title, sizeof(title),
322-
ev_name);
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);
323339
ui_browser__show_title(&self->b, title);
324340
continue;
325341
case 'D': { /* Debug */
@@ -883,7 +899,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
883899
goto out_free_stack;
884900
case 'a':
885901
if (!browser->has_symbols) {
886-
ui_browser__warning(&browser->b,
902+
ui_browser__warning(&browser->b, delay_secs * 2,
887903
"Annotation is only available for symbolic views, "
888904
"include \"sym\" in --sort to use it.");
889905
continue;
@@ -1061,6 +1077,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
10611077
struct perf_evsel_menu {
10621078
struct ui_browser b;
10631079
struct perf_evsel *selection;
1080+
bool lost_events, lost_events_warned;
10641081
};
10651082

10661083
static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1073,14 +1090,29 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
10731090
unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
10741091
const char *ev_name = event_name(evsel);
10751092
char bf[256], unit;
1093+
const char *warn = " ";
1094+
size_t printed;
10761095

10771096
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
10781097
HE_COLORSET_NORMAL);
10791098

10801099
nr_events = convert_unit(nr_events, &unit);
1081-
snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1082-
unit, unit == ' ' ? "" : " ", ev_name);
1083-
slsmg_write_nstring(bf, browser->width);
1100+
printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1101+
unit, unit == ' ' ? "" : " ", ev_name);
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);
10841116

10851117
if (current_entry)
10861118
menu->selection = evsel;
@@ -1105,6 +1137,11 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
11051137
switch (key) {
11061138
case K_TIMER:
11071139
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+
}
11081145
continue;
11091146
case K_RIGHT:
11101147
case K_ENTER:

0 commit comments

Comments
 (0)