fix(profiler): demangle native C++ symbols in profiler reports#339
Merged
Conversation
Perf stores frame names mangled, so profiler-stack-query stacks read like `_ZN16GrDrawingManager5flushE6SkSpan...` - accurate but hard to read. Add a conservative, best-effort Itanium demangler (nested names + plain function names, argument list dropped, internal `.__uniq`/`.llvm` suffixes stripped) and apply it when rendering function_callers and hang_stacks output. Anything it can't confidently parse - templates, substitutions, kernel C symbols - is returned verbatim, so it never corrupts a name. SQL matching upstream still uses the raw mangled names, so this is display-only.
The drill-downs (function_callers / hang_stacks) were demangled, but the CPU Hotspots table, its detail headings, and the Suggested Improvements bullets still showed the raw mangled leaf name (e.g. `_ZN16GrDrawingManager5flushE...`) — the most visible output. Apply demangleSymbol at those human-facing display sites. The Next Steps copy-paste `function_callers` suggestion deliberately keeps the raw symbol: it's matched as a SQL substring of the mangled frame, and the demangled name (args dropped) isn't a substring of it. Also dedup overloaded leaf symbols AFTER demangling in the function_callers substring note, so two overloads (`_ZN3foo3barEv`/`_ZN3foo3barEi`, both `foo::bar`) collapse to one bullet instead of printing the same line twice while the count says 2.
hubgan
reviewed
Jun 16, 2026
… too The detail-block heading was demangled but the call chains right under it (topCallChains, and the single-chain fallback) still rendered raw frames. On Android those chains are built from the same mangled leaf_function as the heading, so the report showed `GrDrawingManager::flush` over a chain reading `_ZN16GrDrawingManager5flushE...` for the very same function. Map each frame through demangleSymbol (display-only; the function_callers suggestion still keeps the raw mangled name for its SQL substring match). Cover both chain-render paths in render-demangle.test.ts.
… (hangs, leaks), not just CPU
hubgan
approved these changes
Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
profiler-stack-queryAndroid stacks come straight from perf, which stores frame names mangled — sofunction_callers/hang_stacksoutput reads like:This adds a conservative, best-effort Itanium demangler and applies it when rendering those stacks (display-only — SQL matching upstream still uses the raw mangled names). The same stack now reads:
What it handles
_ZN...E) and plain function names; the argument list is dropped..__uniq.*,.llvm.*,.part.*,.cold).Test plan
test/android-perfetto/demangle.test.ts(10 cases incl. fallbacks).function-callers.test.tsto expect the demangled leaf in the substring-match note.npm test -w @argent/tool-server— all pass; build +typecheck:testsclean.