From 538d9c1829eddf375436c52604f82ff3f53c6690 Mon Sep 17 00:00:00 2001 From: Stephen Brennan Date: Wed, 1 Sep 2021 14:08:15 -0700 Subject: [PATCH] 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: Stephen Brennan Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20210901210815.133251-1-stephen.s.brennan@oracle.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 13 ++++++++ .../scripting-engines/trace-event-python.c | 32 +++++++++++++++++++ tools/perf/util/trace-event.h | 3 ++ 3 files changed, 48 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f469354155f1..0e824f7d8b19 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -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, }, diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69129e2aa7a1..c0c010350bc2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -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, }; diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 54aadeedf28c..640981105788 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -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); };