From nobody Tue Dec 2 02:19:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B0892D6E6F; Thu, 20 Nov 2025 02:11:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763604662; cv=none; b=NOvWMJuiRh1+OXgP71TP/pL/0P7xpTz3XLZLnVov3kN6BoUYX44SOCe/JYJ3Ftsg8vUKY+g+1U1jegHox5DDBJnZk3LOZS/3r9FNyVdv/XTG1jbqYrsaUUEX+jXVJR1610q9lGEMB0griNauXs8BruE84z92/P2LxIi24xjv0Cw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763604662; c=relaxed/simple; bh=siw+mcZ83tjXm1ovxal++nt/JLHPrue73w1F1ndPwRE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oQvjaxBRX2FPMYk4SzN1ZAYsrR5pOUUUwBaJ+CfjVCQKSADz+3SvNwWkH9jCBmhOt8yiAMxD7XE4WCVRetz8tmYQ8jTxJ+JLoFboFnBIa6jD00xumPLZ9EXC2wxIWVUEZCSjg3zVlzolA28MzMQGav67n3wtdRQVZEVFIWmOinQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eud32Usg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eud32Usg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E88CC16AAE; Thu, 20 Nov 2025 02:11:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1763604662; bh=siw+mcZ83tjXm1ovxal++nt/JLHPrue73w1F1ndPwRE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eud32Usgc3f/G2icCK37SiCaUf90+lfBfUw++mCSiv4YBzcQAI2m0Tp0eKPxU/+B0 Qi7uOEyO8fQT4OAzOXa8gqG74jJjkWG2Qu4N2St0oI+Mfoj7aqwwqEaFREgr0b3RAD oQHKpA43Mj5cVJCLn20JZDC4fsAA1l+uF4xabDkgqiALIdek06BVmr0dcJoPqhNGkF J1Y6e1vzO73CFXOwG1HTJHmemhGdqTtNiKBUkp348Rc5gv0h6Jbw6SCl/I9U9JMjwG a5KyipsPMQxA1VP3S7vGyeQqb7E+gXoP5pU793H4uxMs2Z/K0eMoREgFK7Wi+z8Uny l2GL2YjAMkPqg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , James Clark Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Steven Rostedt , Josh Poimboeuf , Indu Bhagat , Jens Remus , Mathieu Desnoyers , linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org Subject: [PATCH v5 6/6] perf tools: Flush remaining samples w/o deferred callchains Date: Wed, 19 Nov 2025 18:10:46 -0800 Message-ID: <20251120021046.94490-7-namhyung@kernel.org> X-Mailer: git-send-email 2.52.0.rc1.455.g30608eb744-goog In-Reply-To: <20251120021046.94490-1-namhyung@kernel.org> References: <20251120021046.94490-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Also 32-bit systems can see partial mmap for the data. In that case, deferred samples won't point to the correct data once the mapping moves to the next portion of the file. Copy the original sample before it unmaps the current data. Signed-off-by: Namhyung Kim --- tools/perf/util/session.c | 98 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 2e777fd1bcf6707b..b781e01ddcb4876b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1288,8 +1288,13 @@ static int evlist__deliver_sample(struct evlist *evl= ist, const struct perf_tool struct deferred_event { struct list_head list; union perf_event *event; + bool allocated; }; =20 +/* + * This is called when a deferred callchain record comes up. Find all mat= ching + * samples, merge the callchains and process them. + */ static int evlist__deliver_deferred_samples(struct evlist *evlist, const struct perf_tool *tool, union perf_event *event, @@ -1331,6 +1336,86 @@ static int evlist__deliver_deferred_samples(struct e= vlist *evlist, free(orig_sample.callchain); =20 list_del(&de->list); + if (de->allocated) + free(de->event); + free(de); + + if (ret) + break; + } + return ret; +} + +/* + * This is called when the backing mmap is about to go away. It needs to = save + * the original sample data until it finds the matching deferred callchain= s. + */ +static void evlist__copy_deferred_samples(struct evlist *evlist, + const struct perf_tool *tool, + struct machine *machine) +{ + struct deferred_event *de, *tmp; + struct evsel *evsel; + int ret =3D 0; + + list_for_each_entry_safe(de, tmp, &evlist->deferred_samples, list) { + struct perf_sample sample; + size_t sz =3D de->event->header.size; + void *buf; + + if (de->allocated) + continue; + + buf =3D malloc(sz); + if (buf) { + memcpy(buf, de->event, sz); + de->event =3D buf; + de->allocated =3D true; + continue; + } + + /* The allocation failed, flush the sample now */ + ret =3D evlist__parse_sample(evlist, de->event, &sample); + if (ret =3D=3D 0) { + evsel =3D evlist__id2evsel(evlist, sample.id); + evlist__deliver_sample(evlist, tool, de->event, + &sample, evsel, machine); + } + + list_del(&de->list); + BUG_ON(de->allocated); + free(de); + } +} + +/* + * This is called at the end of the data processing for the session. Flus= h the + * remaining samples as there's no hope for matching deferred callchains. + */ +static int evlist__flush_deferred_samples(struct evlist *evlist, + const struct perf_tool *tool, + struct machine *machine) +{ + struct deferred_event *de, *tmp; + struct evsel *evsel; + int ret =3D 0; + + list_for_each_entry_safe(de, tmp, &evlist->deferred_samples, list) { + struct perf_sample sample; + + ret =3D evlist__parse_sample(evlist, de->event, &sample); + if (ret < 0) { + pr_err("failed to parse original sample\n"); + break; + } + + evsel =3D evlist__id2evsel(evlist, sample.id); + ret =3D evlist__deliver_sample(evlist, tool, de->event, + &sample, evsel, machine); + + list_del(&de->list); + if (de->allocated) + free(de->event); free(de); =20 if (ret) @@ -1374,6 +1459,7 @@ static int machines__deliver_event(struct machines *m= achines, return -ENOMEM; =20 de->event =3D event; + de->allocated =3D false; list_add_tail(&de->list, &evlist->deferred_samples); return 0; } @@ -2218,6 +2304,8 @@ reader__mmap(struct reader *rd, struct perf_session *= session) } =20 if (mmaps[rd->mmap_idx]) { + evlist__copy_deferred_samples(session->evlist, session->tool, + &session->machines.host); munmap(mmaps[rd->mmap_idx], rd->mmap_size); mmaps[rd->mmap_idx] =3D NULL; } @@ -2372,6 +2460,11 @@ static int __perf_session__process_events(struct per= f_session *session) if (err) goto out_err; err =3D auxtrace__flush_events(session, tool); + if (err) + goto out_err; + err =3D evlist__flush_deferred_samples(session->evlist, + session->tool, + &session->machines.host); if (err) goto out_err; err =3D perf_session__flush_thread_stacks(session); @@ -2494,6 +2587,11 @@ static int __perf_session__process_dir_events(struct= perf_session *session) if (ret) goto out_err; =20 + ret =3D evlist__flush_deferred_samples(session->evlist, tool, + &session->machines.host); + if (ret) + goto out_err; + ret =3D perf_session__flush_thread_stacks(session); out_err: ui_progress__finish(); --=20 2.52.0.rc1.455.g30608eb744-goog