Skip to content

Import frame line numbers from Chrome profiles#6192

Open
canova wants to merge 3 commits into
firefox-devtools:mainfrom
canova:chrome-line-col
Open

Import frame line numbers from Chrome profiles#6192
canova wants to merge 3 commits into
firefox-devtools:mainfrom
canova:chrome-line-col

Conversation

@canova

@canova canova commented Jul 16, 2026

Copy link
Copy Markdown
Member

Main | Deploy preview

Fixes #6182

It isn't super easy to see what this does without having the source code in the source view. But you can check the frame table to see that we have line and column numbers now.

For example, you can use this chrome trace: Trace-20260715T220108.json.gz

Check the frameTable in the before and after profiles with:

// line numbers
profile.shared.frameTable.line.filter(l => !!l)

// and column
profile.shared.frameTable.column.filter(c => !!c)

It'll look like now we have less information in the frame table, but no. Previously, we were always adding the line and column of the function definition, which wasn't correct. Now these numbers are in the funcTable. And we only have line and column number if the frame truly has line/column. Otherwise we omit that information.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.90110% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.66%. Comparing base (d4b6ff9) to head (d0d8a6b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/profile-logic/import/chrome.ts 98.90% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6192      +/-   ##
==========================================
+ Coverage   83.63%   83.66%   +0.02%     
==========================================
  Files         346      346              
  Lines       37174    37248      +74     
  Branches    10318    10441     +123     
==========================================
+ Hits        31090    31163      +73     
- Misses       5656     5657       +1     
  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.

canova added 3 commits July 20, 2026 10:34
The Chrome/Node importer derived each frame's index from `nodeIndex - 1`
and wrote into the shared global frame table. Because V8 node ids restart
at 1 for every thread, two threads' node 1 both mapped to frame 0, so the
later thread clobbered the earlier thread's frame data (func, category,
line) while the earlier thread's stacks still pointed at it.

Allocate a fresh frame index from `frameTable.length` for each node
instead. This is also a prerequisite for emitting more than one frame per
node.
V8 cpuprofiles carry two kinds of source locations per node: callFrame
contains the function definition location, while positionTicks is the
per-line breakdown of where the function self time was spent. We only
imported the former, so the source view attributed all of a function
self time to its definition line.

Keep the definition location in the func table and use a neutral
structural frame for the node so descendant samples do not inherit an
arbitrary executed line. Create a sibling frame for every distinct valid
positionTicks line and distribute only the node leaf samples among them
in proportion to the tick counts using deterministic largest-deficit
rounding. Leave their columns null because positionTicks does not
contain column data, and ignore positionTicks on native frames without a
source.

positionTicks lines are 1-based, unlike the 0-based callFrame line
number.
The DevTools trace-event ProfileChunk format records the executed source
line and column for each sample in args.data.lines and
args.data.columns, parallel to cpuProfile.samples, rather than the
per-node positionTicks of the .cpuprofile format.

Read these arrays and put each emitted sample to a frame carrying its
executed line. The frame is created lazily as a sibling of the node base
stack. Native frames without a source fall back to the base stack, and
the positionTicks path stays as a fallback when no per-sample line is
present.
@canova
canova force-pushed the chrome-line-col branch from c2fa147 to d0d8a6b Compare July 20, 2026 08:34
@canova
canova requested review from fatadel and mstange July 20, 2026 08:42
@canova
canova marked this pull request as ready for review July 20, 2026 08:42
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.

Chrome importer drops frame level line number information

1 participant