perf sched: Handle missing trace samples in pipe mode

For pipe mode streams, event attributes are received dynamically during
event processing, meaning session->evlist is not populated prior to
perf_session__process_events(). To handle pipe input correctly:
  - Register the missing .attr, .tracing_data, .build_id, and .feature
    callbacks in cmd_sched()

  - Promote the handlers array to file-scope (latency_handlers[]) and
    dynamically assign matching tracepoint handlers
    (or process_sched_ignore) inside
    perf_sched__process_tracepoint_sample() when evsel->handler is NULL;
    replace process_sched_wakeup_ignore() with process_sched_ignore()

  - Perform the trace check post-processing when handling pipe data

Fixes: 27295592c2 ("perf session: Share the common trace sample_check routine as perf_session__has_traces")
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Aaron Tomlin 2026-08-06 11:39:24 -04:00 committed by Namhyung Kim
parent 4a81d59a9d
commit 44f8dd1ee1

View File

@ -1581,12 +1581,6 @@ static int process_sched_wakeup_event(const struct perf_tool *tool,
return 0;
}
static int process_sched_wakeup_ignore(const struct perf_tool *tool __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
{
return 0;
}
static bool thread__has_color(struct thread *thread)
{
@ -1938,6 +1932,22 @@ typedef int (*tracepoint_handler)(const struct perf_tool *tool,
struct perf_sample *sample,
struct machine *machine);
static struct evsel_str_handler latency_handlers[] = {
{ "sched:sched_switch", process_sched_switch_event, },
{ "sched:sched_stat_runtime", process_sched_runtime_event, },
{ "sched:sched_wakeup", process_sched_wakeup_event, },
{ "sched:sched_waking", process_sched_wakeup_event, },
{ "sched:sched_wakeup_new", process_sched_wakeup_event, },
{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
};
static int process_sched_ignore(const struct perf_tool *tool __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
{
return 0;
}
static int perf_sched__process_tracepoint_sample(const struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
struct perf_sample *sample,
@ -1946,7 +1956,23 @@ static int perf_sched__process_tracepoint_sample(const struct perf_tool *tool __
struct evsel *evsel = sample->evsel;
int err = 0;
if (evsel->handler != NULL) {
if (evsel->handler == NULL) {
evsel->handler = process_sched_ignore;
for (size_t i = 0; i < ARRAY_SIZE(latency_handlers); i++) {
if (!evsel__name_is(evsel, latency_handlers[i].name))
continue;
if (!strcmp(latency_handlers[i].name, "sched:sched_wakeup") &&
sample->evsel->evlist &&
evlist__find_tracepoint_by_name(sample->evsel->evlist, "sched:sched_waking"))
break;
evsel->handler = latency_handlers[i].handler;
break;
}
}
if (evsel->handler != process_sched_ignore) {
tracepoint_handler f = evsel->handler;
err = f(tool, sample, machine);
}
@ -1987,14 +2013,6 @@ static int perf_sched__process_comm(const struct perf_tool *tool __maybe_unused,
static int perf_sched__read_events(struct perf_sched *sched)
{
struct evsel_str_handler handlers[] = {
{ "sched:sched_switch", process_sched_switch_event, },
{ "sched:sched_stat_runtime", process_sched_runtime_event, },
{ "sched:sched_wakeup", process_sched_wakeup_event, },
{ "sched:sched_waking", process_sched_wakeup_event, },
{ "sched:sched_wakeup_new", process_sched_wakeup_event, },
{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
};
struct perf_session *session;
struct perf_data data = {
.path = input_name,
@ -2011,14 +2029,17 @@ static int perf_sched__read_events(struct perf_sched *sched)
symbol__init(perf_session__env(session));
/* prefer sched_waking if it is captured */
if (evlist__find_tracepoint_by_name(session->evlist, "sched:sched_waking"))
handlers[2].handler = process_sched_wakeup_ignore;
if (!perf_data__is_pipe(session->data)) {
/* prefer sched_waking if it is captured */
if (evlist__find_tracepoint_by_name(session->evlist, "sched:sched_waking"))
latency_handlers[2].handler = process_sched_ignore;
if (perf_session__set_tracepoints_handlers(session, handlers))
goto out_delete;
if (perf_session__set_tracepoints_handlers(session, latency_handlers))
goto out_delete;
}
if (!perf_session__has_traces(session, "record -R"))
if (!perf_data__is_pipe(session->data) &&
!perf_session__has_traces(session, "record -R"))
goto out_delete;
err = perf_session__process_events(session);
@ -2027,6 +2048,11 @@ static int perf_sched__read_events(struct perf_sched *sched)
goto out_delete;
}
if (perf_data__is_pipe(session->data) &&
!perf_session__has_traces(session, "record -R")) {
goto out_delete;
}
sched->nr_events = evlist__stats(session->evlist)->nr_events[0];
sched->nr_lost_events = evlist__stats(session->evlist)->total_lost;
sched->nr_lost_chunks = evlist__stats(session->evlist)->nr_events[PERF_RECORD_LOST];
@ -5176,6 +5202,10 @@ int cmd_sched(int argc, const char **argv)
sched.tool.namespaces = perf_event__process_namespaces;
sched.tool.lost = perf_event__process_lost;
sched.tool.fork = perf_sched__process_fork_event;
sched.tool.attr = perf_event__process_attr;
sched.tool.tracing_data = perf_event__process_tracing_data;
sched.tool.build_id = perf_event__process_build_id;
sched.tool.feature = perf_event__process_feature;
argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);