From: Matthew Wood <thepacketgeek@gmail.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>
Cc: linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: [PATCH v3 0/2] perf unwind: Don't load symbols when the caller doesn't need them
Date: Fri, 30 Oct 2026 12:32:32 -0700 [thread overview]
Message-ID: <20261030193237.1440673-1-thepacketgeek@gmail.com> (raw)
When perf only needs to know which DSOs a callchain passes through (as
build-id marking does at the end of 'perf record' and in 'perf inject
-b') it resolves the callchain without symbols. The DWARF unwinders
ignore that and look up the symbol of every frame anyway, which loads
and demangles the whole symbol table of each DSO they visit.
On arm64 every frame pointer sample also gets a short DWARF
unwind to find the leaf function's caller; since v6.17 (commit
29be60c93d2d, "perf build-id: Mark DSO in sample callchains") the end of
'perf record -a --call-graph fp' loads the symbols of every user binary
it sampled. On a 128-CPU arm64 host,
perf record -a -e cycles:u --call-graph fp -- sleep 2
never finishes writing perf.data, with over 1GB of heap growth in 5
seconds.
Skipping the symbol lookup isn't enough because loading the
symbols also finds two things the unwinders depend on: the DSO's
build-id, which libdw needs to fall back to the build-id cache, and any
separate debuginfo file, through dso__symsrc_filename(), which is how
both unwinders find a .debug_frame there.
1: add dso__load_symsrc(), which does the same search for debuginfo
and the build-id as symbol loading, but doesn't read any symbols
2: pass the symbols flag down to the unwinders and honour it, using
dso__load_symsrc() when symbols aren't wanted, which also makes
the arm64 leaf frame caller unwind skip symbols
Testing compared v7.3-rc7 with this series, on x86 and natively on a
CentOS Stream 10 arm64 host:
- The 'perf test' dwarf unwind and 'perf inject' DWARF callchain
conversion tests pass on both, also in a REFCNT_CHECKING build on
x86. The libdw multi-threaded unwind and addr2line inline unwinding
tests pass on x86; on the arm64 host the former is skipped and the
latter fails both with and without this series.
- 'perf inject -b' on an x86 'perf record --call-graph dwarf' profile
of a Python workload goes from 0.19s and 69MB max RSS to 0.10s and
33MB, with the same build-ids injected.
- A test library built with -fno-asynchronous-unwind-tables, so that
its CFI is only in .debug_frame, then split with 'objcopy
--only-keep-debug', sits between two other DSOs in the sampled
stacks. On both architectures, with the debuginfo found either
through .gnu_debuglink or only in perf's build-id cache, 'perf
script' output for a --call-graph dwarf profile, and on arm64 for an
fp profile, is unchanged with both libdw and libunwind, and 'perf
inject -b' unwinds the same frames and marks the same DSOs. v1,
which only passed the flag down, lost every frame past the library
in all but 5 of 4045 samples in 'perf script'.
libunwind's .debug_frame support couldn't be exercised: EL9's x86
libunwind is built without it, and on arm64 perf's libunwind support
has been compiled out since v7.2, as libunwind-arm64.c checks
HAVE_LIBUNWIND_ARM64_SUPPORT while Makefile.config defines
HAVE_LIBUNWIND_AARCH64_SUPPORT. With that macro defined by hand, and a
cast for the build error it then hits, arm64 libunwind results are also
the same with and without this series. That breakage is independent of
this series.
Not tested: the build-id cache fallback for DSOs in another mount
namespace when the MMAP2 events don't carry build-ids.
Changes since v2:
- Instead of a separate debuginfo lookup, reuse dso__load()'s search
and stop before reading symbols (dso__load_symsrc()) so candidate
files are checked against the build-id, --symfs, mount namespaces
and chroots are honoured, and the search is done once per DSO
- Drop moving dso__read_build_id() out of 'perf inject'
- Extend the dwarf unwind test to unwind without symbols, check that
no symbols get loaded, and compare with unwinding with symbols
- Link:
https://lore.kernel.org/all/20261017000158.1178269-1-thepacketgeek@gmail.com/
Changes since v1:
- Complete re-work on approach based on feedback
- Link: https://lore.kernel.org/linux-perf-users/20261014151326.4142140-1-thepacketgeek@gmail.com/
Matthew Wood (2):
perf symbol: Add dso__load_symsrc()
perf unwind: Don't look up symbols when the caller doesn't want them
tools/perf/tests/dwarf-unwind.c | 71 ++++++++++++++++---
.../util/arm64-frame-pointer-unwind-support.c | 7 +-
tools/perf/util/dso.h | 11 +++
tools/perf/util/machine.c | 7 +-
tools/perf/util/symbol.c | 40 +++++++++--
tools/perf/util/symbol.h | 1 +
tools/perf/util/unwind-libdw.c | 17 ++++-
tools/perf/util/unwind-libdw.h | 1 +
tools/perf/util/unwind-libunwind.c | 22 ++++--
tools/perf/util/unwind.c | 7 +-
tools/perf/util/unwind.h | 11 ++-
11 files changed, 164 insertions(+), 31 deletions(-)
base-commit: 24a19b953e2a3d0ea5a8c4951a0ab8f32720c907
--
2.53.0-Meta
next reply other threads:[~2026-10-30 19:32 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 19:32 Matthew Wood [this message]
2026-10-30 19:32 ` [PATCH v3 1/2] perf symbol: Add dso__load_symsrc() Matthew Wood
2026-10-30 19:32 ` [PATCH v3 2/2] perf unwind: Don't look up symbols when the caller doesn't want them Matthew Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261030193237.1440673-1-thepacketgeek@gmail.com \
--to=thepacketgeek@gmail.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®