Skip to content

feat: invert call stack in flame graph to render as icicle graph#6090

Open
cathaysia wants to merge 3 commits into
firefox-devtools:mainfrom
cathaysia:feat/icicle_graph
Open

feat: invert call stack in flame graph to render as icicle graph#6090
cathaysia wants to merge 3 commits into
firefox-devtools:mainfrom
cathaysia:feat/icicle_graph

Conversation

@cathaysia

@cathaysia cathaysia commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
image

add a invert callstack checkbox.

before:

image

after:
image

fix #6077

@cathaysia cathaysia force-pushed the feat/icicle_graph branch from 4f7ab4e to 2e38000 Compare June 5, 2026 02:46
@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.04082% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.33%. Comparing base (2cb282f) to head (1f13270).
⚠️ Report is 75 commits behind head on main.

Files with missing lines Patch % Lines
src/profile-logic/flame-graph.ts 72.26% 38 Missing ⚠️
src/selectors/per-thread/stack-sample.ts 81.48% 5 Missing ⚠️
src/components/flame-graph/Canvas.tsx 92.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6090      +/-   ##
==========================================
- Coverage   83.69%   83.33%   -0.36%     
==========================================
  Files         338      339       +1     
  Lines       35693    36098     +405     
  Branches     9904    10096     +192     
==========================================
+ Hits        29873    30084     +211     
- Misses       5392     5586     +194     
  Partials      428      428              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cathaysia

Copy link
Copy Markdown
Contributor Author

Hello, is anyone reviewing this PR? I don't have the permission to request a review.

@cathaysia

Copy link
Copy Markdown
Contributor Author

@mstange

mstange commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Unfortunately this implementation is too slow on large profiles. For example, clicking the "Invert call stack" checkbox on this flame graph causes the page to hang permanently:

https://deploy-preview-6090--perf-html.netlify.app/public/54908b38j3brzm4vw7mw3k3sqn3sf6vzfe95sxg/flame-graph/?globalTrackOrder=d59g1b7feac8x63402s6rx0mx4x3jthvilpnx5ux1qox2k&hiddenGlobalTracks=0wcewx6&profileName=Firefox%20Win%20Sp3%2015x%2020260304&thread=d&v=16

Furthermore, I think this view is only useful if most of the time is spent in a single leaf function. Once you have time spread over many different leaves, the inverted flame graph becomes less useful because all the root nodes will be very small boxes, and then their children are even smaller boxes.

However, what can be useful is the inverted flame graph for a single leaf function. In #5233 I'm prototyping a panel where you can select a function on the left side, and then see flame graphs for that function on the right side. When limited to a single function, computing the inverted flame graph can be done in reasonable time because the number of nodes in the tree is much more limited.

Here's an example:

https://deploy-preview-5233--perf-html.netlify.app/public/54908b38j3brzm4vw7mw3k3sqn3sf6vzfe95sxg/function-list/?funcListSections=descendants%2Cancestors&globalTrackOrder=d59g1b7feac8x63402s6rx0mx4x3jthvilpnx5ux1qox2k&hiddenGlobalTracks=0wcewx6&profileName=Firefox%20Win%20Sp3%2015x%2020260304&selectedFunc=23546&thread=d&v=17

@cathaysia

Copy link
Copy Markdown
Contributor Author

Thanks for the large-profile test case. I reproduced the hang locally with the profile from the preview link: computing the inverted flame graph timing for thread d ran out of memory with an 8GB JS heap.

I pushed 1f13270a2 to address this:

  • non-inverted flame graphs are back on the original FlameGraphRows + getFlameGraphTiming path, so they no longer go through the generic CallTree traversal;
  • inverted flame graphs now use a dedicated timing builder based on CallNodeInfoInverted + CallTreeTimingsInverted, avoiding CallTree.getNodeData() and the display-layer traversal;
  • the inverted builder prunes boxes narrower than 1 / 16384, because the flame graph has no horizontal zoom and those boxes cannot be meaningfully read or hovered even on very wide displays. This also avoids materializing huge invisible inverted subtrees.

With the same large profile / thread d, the selector now completes locally in about 1.6s and produces 242 rows / 42,238 boxes instead of OOMing.

I also added a regression test for the same-name-node case so the inverted tree does not combine unrelated call paths such as A -> B -> C and A -> C -> D into impossible paths.

@cathaysia

Copy link
Copy Markdown
Contributor Author

Actually, I think it would be more appropriate to move the data processing part to WASM. Rust can precisely control memory, and Rust itself provides many tools for benchmarking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support icicle graph

2 participants