Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b27509f authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo
Browse files

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 <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-47yyqbubmjzch2chezmb21m6@git.kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1ca4ff41
Loading
Loading
Loading
Loading
+26 −11
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ static bool vmlinux_warned;
static bool			inherit				=  false;
static int			realtime_prio			=      0;
static bool			group				=  false;
static bool			sample_id_all_avail		=   true;
static unsigned int		mmap_pages			=    128;

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

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

	if (top.total_lost_warned != top.session->hists.stats.total_lost) {
		top.total_lost_warned = top.session->hists.stats.total_lost;
		color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
		printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
		       top.total_lost_warned);
	if (top.sym_evsel->hists.stats.nr_lost_warned !=
	    top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
		top.sym_evsel->hists.stats.nr_lost_warned =
			top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
		color_fprintf(stdout, PERF_COLOR_RED,
			      "WARNING: LOST %d chunks, Check IO/CPU overload",
			      top.sym_evsel->hists.stats.nr_lost_warned);
		++printed;
	}

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

static void perf_event__process_sample(const union perf_event *event,
				       struct perf_evsel *evsel,
				       struct perf_sample *sample,
				       struct perf_session *session)
{
@@ -770,12 +774,8 @@ static void perf_event__process_sample(const union perf_event *event,
	}

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

		evsel = perf_evlist__id2evsel(top.evlist, sample->id);
		assert(evsel != NULL);

		if ((sort__has_parent || symbol_conf.use_callchain) &&
		    sample->callchain) {
			err = perf_session__resolve_callchain(session, al.thread,
@@ -807,6 +807,7 @@ static void perf_event__process_sample(const union perf_event *event,
static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
{
	struct perf_sample sample;
	struct perf_evsel *evsel;
	union perf_event *event;
	int ret;

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

		evsel = perf_evlist__id2evsel(self->evlist, sample.id);
		assert(evsel != NULL);

		if (event->header.type == PERF_RECORD_SAMPLE)
			perf_event__process_sample(event, &sample, self);
		else
			perf_event__process_sample(event, evsel, &sample, self);
		else if (event->header.type < PERF_RECORD_MAX) {
			hists__inc_nr_events(&evsel->hists, event->header.type);
			perf_event__process(event, &sample, self);
		} else
			++self->hists.stats.nr_unknown_events;
	}
}

@@ -864,6 +871,8 @@ static void start_counters(struct perf_evlist *evlist)
		attr->mmap = 1;
		attr->comm = 1;
		attr->inherit = inherit;
retry_sample_id:
		attr->sample_id_all = sample_id_all_avail ? 1 : 0;
try_again:
		if (perf_evsel__open(counter, top.evlist->cpus,
				     top.evlist->threads, group,
@@ -873,6 +882,12 @@ static void start_counters(struct perf_evlist *evlist)
			if (err == EPERM || err == EACCES) {
				ui__error_paranoid();
				goto out_err;
			} else if (err == EINVAL && sample_id_all_avail) {
				/*
				 * Old kernel, no attr->sample_id_type_all field
				 */
				sample_id_all_avail = false;
				goto retry_sample_id;
			}
			/*
			 * If it's cycles then fall back to hrtimer
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ struct events_stats {
	u64 total_lost;
	u64 total_invalid_chains;
	u32 nr_events[PERF_RECORD_HEADER_MAX];
	u32 nr_lost_warned;
	u32 nr_unknown_events;
	u32 nr_invalid_chains;
	u32 nr_unknown_id;
+23 −6
Original line number Diff line number Diff line
@@ -738,10 +738,27 @@ static int perf_session_deliver_event(struct perf_session *session,

	dump_event(session, event, file_offset, sample);

	evsel = perf_evlist__id2evsel(session->evlist, sample->id);
	if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) {
		/*
		 * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here
		 * because the tools right now may apply filters, discarding
		 * some of the samples. For consistency, in the future we
		 * should have something like nr_filtered_samples and remove
		 * the sample->period from total_sample_period, etc, KISS for
		 * now tho.
		 *
		 * Also testing against NULL allows us to handle files without
		 * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the
		 * future probably it'll be a good idea to restrict event
		 * processing via perf_session to files with both set.
		 */
		hists__inc_nr_events(&evsel->hists, event->header.type);
	}

	switch (event->header.type) {
	case PERF_RECORD_SAMPLE:
		dump_sample(session, event, sample);
		evsel = perf_evlist__id2evsel(session->evlist, sample->id);
		if (evsel == NULL) {
			++session->hists.stats.nr_unknown_id;
			return -1;
@@ -874,11 +891,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
					    const struct perf_event_ops *ops)
{
	if (ops->lost == perf_event__process_lost &&
	    session->hists.stats.total_lost != 0) {
		ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
			    "!\n\nCheck IO/CPU overload!\n\n",
			    session->hists.stats.total_period,
			    session->hists.stats.total_lost);
	    session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
		ui__warning("Processed %d events and lost %d chunks!\n\n"
			    "Check IO/CPU overload!\n\n",
			    session->hists.stats.nr_events[0],
			    session->hists.stats.nr_events[PERF_RECORD_LOST]);
	}

	if (session->hists.stats.nr_unknown_events != 0) {
+0 −1
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ struct perf_top {
	u64		   kernel_samples, us_samples;
	u64		   exact_samples;
	u64		   guest_us_samples, guest_kernel_samples;
	u64		   total_lost_warned;
	int		   print_entries, count_filter, delay_secs;
	int		   freq;
	pid_t		   target_pid, target_tid;
+17 −4
Original line number Diff line number Diff line
@@ -176,15 +176,28 @@ void ui_browser__handle_resize(struct ui_browser *browser)
	ui_browser__refresh(browser);
}

int ui_browser__warning(struct ui_browser *browser, const char *format, ...)
int ui_browser__warning(struct ui_browser *browser, int timeout,
			const char *format, ...)
{
	va_list args;
	int key;
	char *text;
	int key = 0, err;

	va_start(args, format);
	while ((key = __ui__warning("Warning!", format, args)) == K_RESIZE)
		ui_browser__handle_resize(browser);
	err = vasprintf(&text, format, args);
	va_end(args);

	if (err < 0) {
		va_start(args, format);
		ui_helpline__vpush(format, args);
		va_end(args);
	} else {
		while ((key == ui__question_window("Warning!", text,
						   "Press any key...",
						   timeout)) == K_RESIZE)
			ui_browser__handle_resize(browser);
		free(text);
	}

	return key;
}
Loading