Re: [PATCH 3/5] perf symbol: Grow the Rust demangle buffer geometrically
From: Namhyung Kim
Date: Tue Oct 06 2026 - 16:06:33 EST
On Mon, Sep 28, 2026 at 02:43:21PM -0700, Ian Rogers wrote:
> On Sun, Sep 27, 2026 at 6:02 PM Michal Pluta <michalpl2003@xxxxxxxxx> wrote:
> >
> > When a demangled Rust name doesn't fit in the provided buffer,
> > dso__demangle_sym() adds 32 bytes to it and formats the name again from
> > the start. The number of attempts grows with the length of the output,
> > so the total work is quadratic. Names with deeply nested generic types
> > need many attempts, leading to noticeable slowdowns in larger programs.
> >
> > Double the buffer instead, reaching the maximum buffer limit exactly
> > rather than stopping 32 bytes early. The demangled names are
> > unchanged.
> >
> > Add a test for a symbol whose expansion exceeds the bound.
> >
> > Signed-off-by: Michal Pluta <michalpl2003@xxxxxxxxx>
> > ---
> > tools/perf/tests/demangle-rust-v0-test.c | 12 ++++++++++++
> > tools/perf/util/symbol.c | 10 ++++++++--
> > 2 files changed, 20 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/perf/tests/demangle-rust-v0-test.c b/tools/perf/tests/demangle-rust-v0-test.c
> > index ee4ddb61174b..d1e0636d73bc 100644
> > --- a/tools/perf/tests/demangle-rust-v0-test.c
> > +++ b/tools/perf/tests/demangle-rust-v0-test.c
> > @@ -69,6 +69,18 @@ static int test__demangle_rust(struct test_suite *test __maybe_unused, int subte
> > free(buf);
> > }
> >
> > + /*
> > + * A symbol with more lifetimes bound than fit in the largest buffer
> > + * must fail to demangle rather than give a truncated name.
> > + */
> > + buf = dso__demangle_sym(/*dso=*/NULL, /*kmodule=*/0, "_RINvC1a1fFGZZZZZZ_EuE");
> > + if (buf) {
> > + pr_debug("FAILED: symbol larger than the buffer limit demangled to %zu bytes\n",
> > + strlen(buf));
> > + ret = TEST_FAIL;
> > + free(buf);
> > + }
> > +
> > return ret;
> > }
> >
> > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> > index 3cb42805a82f..1a52bc2980a0 100644
> > --- a/tools/perf/util/symbol.c
> > +++ b/tools/perf/util/symbol.c
> > @@ -2737,29 +2737,35 @@ char *cxx_demangle_sym(const char *str __maybe_unused, bool params __maybe_unuse
> > }
> > #endif /* !HAVE_CXA_DEMANGLE_SUPPORT */
> >
> > +/* Buffer limit for a demangled Rust symbol name. */
> > +#define RUST_DEMANGLE_MAX_LEN (1024 * 1024)
> > +
> > char *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
> > {
> > struct demangle rust_demangle = {
> > .style = DemangleStyleUnknown,
> > };
> > char *demangled = NULL;
> > + size_t buf_len;
>
> It seems changing the scope of this variable is unnecessary.
>
> >
> > /*
> > * We need to figure out if the object was created from C++ sources
> > * DWARF DW_compile_unit has this, but we don't always have access
> > * to it...
> > */
> > if (!want_demangle((dso && dso__kernel(dso)) || kmodule))
> > return demangled;
> >
> > rust_demangle_demangle(elf_name, &rust_demangle);
> > if (rust_demangle_is_known(&rust_demangle)) {
> > /* A rust mangled name. */
> > if (rust_demangle.mangled_len == 0)
> > return demangled;
> >
> > - for (size_t buf_len = roundup_pow_of_two(rust_demangle.mangled_len * 2);
> > - buf_len < 1024 * 1024; buf_len += 32) {
> > + for (buf_len = min_t(size_t, roundup_pow_of_two(rust_demangle.mangled_len * 2),
> > + RUST_DEMANGLE_MAX_LEN);
> > + buf_len <= RUST_DEMANGLE_MAX_LEN;
> > + buf_len *= 2) {
>
> Thanks for digging into this problem and exploring a fix! Previously,
> we guessed the demangled length was twice the mangled length, then
> added 32 bytes for each retry. These were numbers I pulled out of thin
> air, so I'm glad you've found them to be wrong :-). Could we estimate
> the initial demangled size better? Could you get data from Bevy and
> Typst? I'm a little concerned that a demangled symbol of say just over
> 2KB might require 4KB with this change, instead of 2KB + 32bytes.
I guess it's hard to predict a good initial size as backrefs can make
long strings easily. If we really care about the memory usage, how
about calling realloc() for the actual length at the end?
Thanks,
Namhyung