On Thu, Nov 20, 2025 at 3:48 PM Namhyung Kim <[email protected]> wrote: > > It's possible that some kernel samples don't have matching deferred > callchain records when the profiling session was ended before the > threads came back to userspace. Let's flush the samples before > finish the session. > > Signed-off-by: Namhyung Kim <[email protected]>
Reviewed-by: Ian Rogers <[email protected]> Thanks, Ian > --- > tools/perf/util/session.c | 50 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 50 insertions(+) > > diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c > index dc570ad47ccc2c63..4236503c8f6c1350 100644 > --- a/tools/perf/util/session.c > +++ b/tools/perf/util/session.c > @@ -1295,6 +1295,10 @@ struct deferred_event { > union perf_event *event; > }; > > +/* > + * This is called when a deferred callchain record comes up. Find all > matching > + * samples, merge the callchains and process them. > + */ > static int evlist__deliver_deferred_callchain(struct evlist *evlist, > const struct perf_tool *tool, > union perf_event *event, > @@ -1345,6 +1349,42 @@ static int evlist__deliver_deferred_callchain(struct > evlist *evlist, > return ret; > } > > +/* > + * This is called at the end of the data processing for the session. Flush > the > + * remaining samples as there's no hope for matching deferred callchains. > + */ > +static int session__flush_deferred_samples(struct perf_session *session, > + const struct perf_tool *tool) > +{ > + struct evlist *evlist = session->evlist; > + struct machine *machine = &session->machines.host; > + struct deferred_event *de, *tmp; > + struct evsel *evsel; > + int ret = 0; > + > + list_for_each_entry_safe(de, tmp, &evlist->deferred_samples, list) { > + struct perf_sample sample; > + > + ret = evlist__parse_sample(evlist, de->event, &sample); > + if (ret < 0) { > + pr_err("failed to parse original sample\n"); > + break; > + } > + > + evsel = evlist__id2evsel(evlist, sample.id); > + ret = evlist__deliver_sample(evlist, tool, de->event, > + &sample, evsel, machine); > + > + list_del(&de->list); > + free(de->event); > + free(de); > + > + if (ret) > + break; > + } > + return ret; > +} > + > static int machines__deliver_event(struct machines *machines, > struct evlist *evlist, > union perf_event *event, > @@ -2038,6 +2078,9 @@ static int __perf_session__process_pipe_events(struct > perf_session *session) > done: > /* do the final flush for ordered samples */ > err = ordered_events__flush(oe, OE_FLUSH__FINAL); > + if (err) > + goto out_err; > + err = session__flush_deferred_samples(session, tool); > if (err) > goto out_err; > err = auxtrace__flush_events(session, tool); > @@ -2384,6 +2427,9 @@ static int __perf_session__process_events(struct > perf_session *session) > if (err) > goto out_err; > err = auxtrace__flush_events(session, tool); > + if (err) > + goto out_err; > + err = session__flush_deferred_samples(session, tool); > if (err) > goto out_err; > err = perf_session__flush_thread_stacks(session); > @@ -2506,6 +2552,10 @@ static int __perf_session__process_dir_events(struct > perf_session *session) > if (ret) > goto out_err; > > + ret = session__flush_deferred_samples(session, tool); > + if (ret) > + goto out_err; > + > ret = perf_session__flush_thread_stacks(session); > out_err: > ui_progress__finish(); > -- > 2.52.0.rc2.455.g230fcf2819-goog >
