[draft] ui: flamegraph collection - #7146
Draft
gignat-dev wants to merge 6 commits into
Draft
Conversation
🎨 Perfetto UI Builds
|
gignat-dev
force-pushed
the
dev/gignat/flamegraph_collection
branch
from
August 21, 2026 08:56
053b42c to
20edc2e
Compare
Each metric materializes a persistent flamegraph operator table, cached by metric object identity and dropped only when the QueryFlamegraph is disposed. Callers that cycle through many metric arrays (stepping through profiles, re-filtering a merged set) therefore accumulate one materialized source table per array with no bound. Evict tables whose metric is no longer reachable from the current metrics array at fetch time. The eviction runs inside the query limiter, so it is serialized against every task that creates or reads these tables; switching between metrics of one array still hits the cache.
Introduce FlamegraphCollection (ui/src/components): a view for traces holding many related flamegraphs -- a DataGrid with one row per entry above a flamegraph. The grid's filters select the working set; with Merge on the selection is summed into a single flamegraph, with Merge off the entries are stepped through one at a time (chevrons, arrow keys, click-to-jump) with a shared measure, view and flamegraph filters so entries are compared like for like. Consumers supply rows, columns, a stable entry key and a metricsForKeys(keys) factory; merged mode is metricsForKeys(allWorkingKeys), step mode metricsForKeys([key]) per entry. Grid state persists through a real zod schema, and the arrow-key handler ignores hidden collections (area-selection tabs stay mounted under Gate). Grid id cells derive the entry they highlight and jump to from the row's entry key, never from the displayed text: labels (a thread or process name) need not be unique. DataGrid hands cell renderers only the visible columns' values, so the component fingerprints those against the full data rows to recover the key; a row that cannot be resolved uniquely (the aggregate-totals row, or rows indistinguishable across every visible column) renders inert rather than guessing an entry. In step mode the flamegraph is titled by the entry's display label, falling back to its key. DataGrid's pivot controls are disabled: pivoting would regroup only the grid while the flamegraph keeps reading the flat rows.
An archive with dozens of pprofs currently imports as an undifferentiated blob: every profile lands on the hard-coded "pprof_file" scope. Scope each profile by its source file instead: TraceFileTracker gains a CurrentFile() accessor and the pprof reader walks the file-nesting chain past the gzip layer to the nearest named ancestor. The file id is captured on the first Parse() call -- ParseProfile runs from OnPushDataToSorter, which may fire after the end-of-file notifications have popped the trace-file parsing stack, so reading CurrentFile() there would make scope attribution depend on pipeline ordering. Locations without a pprof mapping each allocated a fresh dummy mapping, so identical frames never interned across profiles and callsites multiplied by the profile count: a 32 MB / 1000-profile archive peaked at 1.8 GB and OOMed the Wasm heap. Intern the shared fallback mapping and skip re-symbolizing interned frames; the same archive now peaks at 647 MB. Diff tests lock the behaviour in: zip/tar members are scoped by member file name (walking past the unnamed gzip layer), directly opened pprofs keep the "pprof_file" scope, duplicate archive members do not duplicate frames/mappings/symbols, and mapping-less locations share a single interned "[unknown]" fallback mapping (asserted with a minimal hand-encoded pprof, since no checked-in pprof lacks mappings).
AggregateProfiles adopts FlamegraphCollection to organize archives: one grid row per profile, one grid column and flamegraph measure per sample type found across the archive. Merging is a single query -- callsites are interned globally, so same-stack samples combine across profiles -- and only the selected subset touches the callstack tables, so the page scales to thousands of profiles. Profile-only traces land on the page directly via initialPage. The Playwright test assembles a tar of the two checked-in pprofs in the test itself (new PerfettoTestHelper.openTraceBuffer), so no new GCS-hosted test data or screenshot baselines are needed.
Each stack-sample area tab (one per profiler source: linux.perf, instruments, chrome, gecko, simpleperf, perf_text, legacy_v8) rendered a single flamegraph merging every selected track. Render a FlamegraphCollection instead: one grid row per selected execution context (thread/process, optionally per profiler session) with its sample count and per-counter totals over the selection window. Merge stays the default, so the previous output is unchanged; the grid adds filtering down to a subset and stepping through contexts one at a time. The context tag-walk, key encoding and SQL fragments move to pure helpers emitting byte-compatible SQL, and metric ids are now stable (counter:<name> / sample_count) so the selected metric survives working-set changes. Persisted per-source FlamegraphStates migrate into the new collection states on load.
The heap-profile area tabs refused any selection spanning more than one process. Render a FlamegraphCollection instead, with one row per process (dump count, allocation totals). flamegraphMetricsForHeapProfile generalizes to a list of upids: each process window is right-extended to its own next dump (per-upid alloc_bound) and the unreleased-allocation classification is keyed (upid, callsite_id), so merging processes never mixes their release accounting and a single upid produces the same window and classification as before. The heap name is now escaped through sqliteString. Persisted per-profile-type FlamegraphStates migrate into the new collection states on load.
gignat-dev
force-pushed
the
dev/gignat/flamegraph_collection
branch
from
August 24, 2026 08:56
20edc2e to
d14b7f1
Compare
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.
No description provided.