Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <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: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Stephen Brennan and committed by
Arnaldo Carvalho de Melo
538d9c18 71f7f897

+48
+13
tools/perf/builtin-script.c
··· 2493 2493 } 2494 2494 2495 2495 static int 2496 + process_throttle_event(struct perf_tool *tool __maybe_unused, 2497 + union perf_event *event, 2498 + struct perf_sample *sample, 2499 + struct machine *machine) 2500 + { 2501 + if (scripting_ops && scripting_ops->process_throttle) 2502 + scripting_ops->process_throttle(event, sample, machine); 2503 + return 0; 2504 + } 2505 + 2506 + static int 2496 2507 process_finished_round_event(struct perf_tool *tool __maybe_unused, 2497 2508 union perf_event *event, 2498 2509 struct ordered_events *oe __maybe_unused) ··· 3663 3652 .stat_config = process_stat_config_event, 3664 3653 .thread_map = process_thread_map_event, 3665 3654 .cpu_map = process_cpu_map_event, 3655 + .throttle = process_throttle_event, 3656 + .unthrottle = process_throttle_event, 3666 3657 .ordered_events = true, 3667 3658 .ordering_requires_timestamps = true, 3668 3659 },
+32
tools/perf/util/scripting-engines/trace-event-python.c
··· 1422 1422 } 1423 1423 } 1424 1424 1425 + static void python_process_throttle(union perf_event *event, 1426 + struct perf_sample *sample, 1427 + struct machine *machine) 1428 + { 1429 + const char *handler_name; 1430 + PyObject *handler, *t; 1431 + 1432 + if (event->header.type == PERF_RECORD_THROTTLE) 1433 + handler_name = "throttle"; 1434 + else 1435 + handler_name = "unthrottle"; 1436 + handler = get_handler(handler_name); 1437 + if (!handler) 1438 + return; 1439 + 1440 + t = tuple_new(6); 1441 + if (!t) 1442 + return; 1443 + 1444 + tuple_set_u64(t, 0, event->throttle.time); 1445 + tuple_set_u64(t, 1, event->throttle.id); 1446 + tuple_set_u64(t, 2, event->throttle.stream_id); 1447 + tuple_set_s32(t, 3, sample->cpu); 1448 + tuple_set_s32(t, 4, sample->pid); 1449 + tuple_set_s32(t, 5, sample->tid); 1450 + 1451 + call_object(handler, t, handler_name); 1452 + 1453 + Py_DECREF(t); 1454 + } 1455 + 1425 1456 static void python_do_process_switch(union perf_event *event, 1426 1457 struct perf_sample *sample, 1427 1458 struct machine *machine) ··· 2110 2079 .process_auxtrace_error = python_process_auxtrace_error, 2111 2080 .process_stat = python_process_stat, 2112 2081 .process_stat_interval = python_process_stat_interval, 2082 + .process_throttle = python_process_throttle, 2113 2083 .generate_script = python_generate_script, 2114 2084 };
+3
tools/perf/util/trace-event.h
··· 90 90 void (*process_stat)(struct perf_stat_config *config, 91 91 struct evsel *evsel, u64 tstamp); 92 92 void (*process_stat_interval)(u64 tstamp); 93 + void (*process_throttle)(union perf_event *event, 94 + struct perf_sample *sample, 95 + struct machine *machine); 93 96 int (*generate_script) (struct tep_handle *pevent, const char *outfile); 94 97 }; 95 98