Commit 538d9c18 authored by Stephen Brennan's avatar Stephen Brennan Committed by Arnaldo Carvalho de Melo
Browse files

perf script python: Allow reporting the [un]throttle PERF_RECORD_ meta event



perf_events may sometimes throttle an event due to creating too many
samples during a given timer tick.

As of now, the perf tool will not report on throttling, which means this
is a silent error.

Implement a callback for the throttle and unthrottle events within the
Python scripting engine, which can allow scripts to detect and report
when events may have been lost due to throttling.

The simplest script to report throttle events is:

  def throttle(*args):
      print("throttle" + repr(args))

  def unthrottle(*args):
      print("unthrottle" + repr(args))

Signed-off-by: default avatarStephen Brennan <stephen.s.brennan@oracle.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20210901210815.133251-1-stephen.s.brennan@oracle.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 71f7f897
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -2492,6 +2492,17 @@ process_lost_event(struct perf_tool *tool,
			   sample->tid);
}

static int
process_throttle_event(struct perf_tool *tool __maybe_unused,
		       union perf_event *event,
		       struct perf_sample *sample,
		       struct machine *machine)
{
	if (scripting_ops && scripting_ops->process_throttle)
		scripting_ops->process_throttle(event, sample, machine);
	return 0;
}

static int
process_finished_round_event(struct perf_tool *tool __maybe_unused,
			     union perf_event *event,
@@ -3652,6 +3663,8 @@ int cmd_script(int argc, const char **argv)
			.stat_config	 = process_stat_config_event,
			.thread_map	 = process_thread_map_event,
			.cpu_map	 = process_cpu_map_event,
			.throttle	 = process_throttle_event,
			.unthrottle	 = process_throttle_event,
			.ordered_events	 = true,
			.ordering_requires_timestamps = true,
		},
+32 −0
Original line number Diff line number Diff line
@@ -1422,6 +1422,37 @@ static void python_process_event(union perf_event *event,
	}
}

static void python_process_throttle(union perf_event *event,
				    struct perf_sample *sample,
				    struct machine *machine)
{
	const char *handler_name;
	PyObject *handler, *t;

	if (event->header.type == PERF_RECORD_THROTTLE)
		handler_name = "throttle";
	else
		handler_name = "unthrottle";
	handler = get_handler(handler_name);
	if (!handler)
		return;

	t = tuple_new(6);
	if (!t)
		return;

	tuple_set_u64(t, 0, event->throttle.time);
	tuple_set_u64(t, 1, event->throttle.id);
	tuple_set_u64(t, 2, event->throttle.stream_id);
	tuple_set_s32(t, 3, sample->cpu);
	tuple_set_s32(t, 4, sample->pid);
	tuple_set_s32(t, 5, sample->tid);

	call_object(handler, t, handler_name);

	Py_DECREF(t);
}

static void python_do_process_switch(union perf_event *event,
				     struct perf_sample *sample,
				     struct machine *machine)
@@ -2079,5 +2110,6 @@ struct scripting_ops python_scripting_ops = {
	.process_auxtrace_error	= python_process_auxtrace_error,
	.process_stat		= python_process_stat,
	.process_stat_interval	= python_process_stat_interval,
	.process_throttle	= python_process_throttle,
	.generate_script	= python_generate_script,
};
+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,9 @@ struct scripting_ops {
	void (*process_stat)(struct perf_stat_config *config,
			     struct evsel *evsel, u64 tstamp);
	void (*process_stat_interval)(u64 tstamp);
	void (*process_throttle)(union perf_event *event,
				 struct perf_sample *sample,
				 struct machine *machine);
	int (*generate_script) (struct tep_handle *pevent, const char *outfile);
};