Skip to content

Deploy June 29, 2026#6131

Merged
canova merged 59 commits into
productionfrom
main
Jun 29, 2026
Merged

Deploy June 29, 2026#6131
canova merged 59 commits into
productionfrom
main

Conversation

@canova

@canova canova commented Jun 29, 2026

Copy link
Copy Markdown
Member

Changes:

[Nazım Can Altınova] Bump profiler-cli version to 0.3.0 (#6104)
[Markus Stange] First typed array: Allow profile.shared.stackTable.frame to be an Int32Array (#6087)
[Nazım Can Altınova] Show more user friendly errors for unsupported profile version in both the frontend and the cli (#6107)
[fatadel] Expose counter information in profiler-cli (#6084)
[Markus Stange] Split getSelfAndTotal. (#6113)
[Markus Stange] Add missing transform shortcut key handling for S (focus-self) (#6117)
[Markus Stange] Remove unused isInverted prop from FlameGraphCanvas. (#6116)
[Markus Stange] Change sidebar splitter CSS to only apply to the sidebar, not to all splitters under .DetailsContainer (#6114)
[Markus Stange] Pass callNodeInfo to handleCallNodeTransformShortcut. (#6115)
[Markus Stange] Move column declarations out into a separate file (#6119)
[fatadel] Keep menu panels above the selected-marker tooltip (#6125)
[Nazım Can Altınova] Make sure to always sanitize source contents even when no PII sanitization is requested (#6127)
[Markus Stange] Compute FlameGraphTiming rows lazily (#6126)
[Markus Stange] Create a non-connected FlameGraph component (#6118)
[Nazım Can Altınova] 🔃 Sync: l10n -> main (June 29, 2026) (#6130)

And special thanks to our localizers:

de: Michael Köhler
el: Jim Spentzos
en-GB: Ian Neal
es-CL: ravmn
fr: Théo Chevalier
fur: Fabio Tomat
fy-NL: Fjoerfoks
ia: Melo46
it: Francesco Lodolo [:flod]
nl: Mark Heijl
ru: Valery Ledovskoy
sv-SE: Luna Jernberg
zh-TW: Pin-guang Chen

mstange and others added 30 commits June 4, 2026 14:44
This doesn't change anything about the profile format, this
is just about the derived in-memory representation.
`JSON.stringify` serializes typed arrays as objects with stringified
numeric keys (e.g. `{"0": 1, "1": 2}`), which is not what we want
when a profile contains typed arrays.

`jsonEncodeObjectWithTypedArraysAsRegularArrays` traverses the object
and converts any typed array it finds to a regular array of numbers
before it calls `JSON.stringify`.

The new function is not used yet; the next patch in this series will
switch profile serialization to use it.
…erialization.

This will allow us to have typed arrays in the profile and
still serialize them as regular JSON arrays whenever the profile
is serialized to JSON.
Some of our tests were auto-stringifying profiles (e.g. the ones using
fetchMock), which will produce bad results once profiles start containing
typed arrays.

Use explicit serializeProfileToJsonString calls in those places.
`RawStackTable` is being prepared to allow `frame` to be an `Int32Array`
in a later commit. `Int32Array` is fixed-size and doesn't support
`push`, so the existing "push to .frame and bump .length" pattern needs
a builder that uses a plain `number[]` during construction and converts
to the final representation via `finishRawStackTableBuilder` at the end.

Switch all stack table construction sites to use the builder. The
builder still produces a plain `number[]` for `frame` in this commit;
the type change happens in a follow-up.
This is the first typed array that we're supporting inside the profile
format.

When a profile is saved in the JsonSlabs format, it will now have this
column as a separate slab that doesn't require JSON parsing.

Profile compacting now always turns `stackTable.frame` into a typed array,
even if that column was a regular JS array in the input profile.

We still allow a regular JSON array here, because profiles stored as JSON 
cannot contain typed arrays, and we want to use the same type definition
for JSON and JSLB profiles.

Here's how this change impacts profile sizes and loading times on
this profile: https://storage.googleapis.com/profiler-get-symbols-fixtures/large-speedometer3-profile.json.gz

| Version | .jslb.gz size | .jslb size | Load time   | Profile of it loading             |
|---------|---------------|------------|-------------|-----------------------------------|
| 64      | 122 MB        | 605 MB     | 7.6 seconds | https://share.firefox.dev/4ogUKba |
| 65      | 125 MB        | 544 MB     | 6.0 seconds | https://share.firefox.dev/3Qopiem |

The compressed size has grown a small bit, but the other savings are significant:

- We no longer have 131 MB of text for the frame column in the JSON - the frame column
  is now stored in a 70 MB i32 slab.
- Less time in GZ decompression, because the uncompressed size is now smaller.
- There is a lot less time spent in TextDecoder.decode and JSON.parse, because we're
  no longer decoding and parsing 131 MB of text for the frame column.
…32Array (#6087)

[Main branch (loading v60 JSLB
profile)](https://main--perf-html.netlify.app/from-url/https%3A%2F%2Fstorage.googleapis.com%2Fprofiler-get-symbols-fixtures%2Flarge-speedometer3-profile.jslb.gz/)
| [Deploy preview (loading v65 JSLB
profile)](https://deploy-preview-6087--perf-html.netlify.app/from-url/https%3A%2F%2Fstorage.googleapis.com%2Fprofiler-get-symbols-fixtures%2Flarge-speedometer3-profile-v65.jslb.gz)

---

This is the first typed array that we're supporting inside the profile
format.

When a profile is saved in the JsonSlabs format, it will now have this
column as a separate slab that doesn't require JSON parsing.

Profile compacting now always turns `stackTable.frame` into a typed
array, even if that column was a regular JS array in the input profile.

We still allow a regular JSON array here, because profiles stored as
JSON cannot contain typed arrays, and we want to use the same type
definition for JSON and JSLB profiles.

Here's how this change impacts profile sizes and loading times on this
profile:
https://storage.googleapis.com/profiler-get-symbols-fixtures/large-speedometer3-profile.json.gz
(with [this corresponding size
profile](https://share.firefox.dev/49IHi9U))

| Version | .jslb.gz size | .jslb size | Load time | Profile of it
loading |

|---------|---------------|------------|-------------|-----------------------------------|
| 64 | 122 MB | 605 MB | 7.6 seconds | https://share.firefox.dev/4ogUKba
|
| 65 | 125 MB | 544 MB | 6.0 seconds | https://share.firefox.dev/3Qopiem
|

The compressed size has grown a small bit, but the other savings are
significant:

- We no longer have 131 MB of text for the frame column in the JSON -
the frame column is now stored in a 70 MB i32 slab.
- Less time in GZ decompression, because the uncompressed size is now
smaller.
- There is a lot less time spent in TextDecoder.decode and JSON.parse,
because we're no longer decoding and parsing 131 MB of text for the
frame column.
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: Nazım Can Altınova <canaltinova@gmail.com>
This will allow us to see the package name from the cli source code and
suggest updating it via npm.
…h the frontend and the cli

I initially wanted to add extra information to the profile version
errors in the cli, because currently we don't give any hint about how
to update it. But while doing that, I realized that we could also
improve the error handling of the frontend a bit more.

The old frontend error was a non-localized text. This commit creates a
new localized text for this type of error and serializes it in a more
friendly way. Probably it's a bit of an overkill for this error as it
should ideally be not seen by the users, but there were existing errors
with the same way, so I wanted to be consistent.

Also, the cli now shows a tip about how to update the cli.
…th the frontend and the cli (#6107)

Fixes #6105 

I initially wanted to add extra information to the profile version
errors in the cli, because currently we don't give any hint about how to
update it. But while doing that, I realized that we could also improve
the error handling of the frontend a bit more.

The old frontend error was a non-localized text. This commit creates a
new localized text for this type of error and serializes it in a more
friendly way. Probably it's a bit of an overkill for this error as it
should ideally be not seen by the users, but there were existing errors
with the same way, so I wanted to be consistent.

Also, the cli now shows a tip about how to update the cli.

Frontend:
Before:
<img width="693" height="417" alt="Screenshot 2026-06-17 at 15 05 53"
src="https://github.com/user-attachments/assets/2cbb8876-4011-4c3e-9fa6-765319f5f4bd"
/>

After:
<img width="758" height="488" alt="Screenshot 2026-06-17 at 15 22 31"
src="https://github.com/user-attachments/assets/96bb0c5a-a6ac-47dd-9f4e-5a3b87274639"
/>

CLI:
Before:
<img width="1227" height="120" alt="Screenshot 2026-06-17 at 15 23 58"
src="https://github.com/user-attachments/assets/e0d52008-6d17-4943-9e2e-cff9a8806ab7"
/>

After:
<img width="1171" height="127" alt="Screenshot 2026-06-17 at 15 03 34"
src="https://github.com/user-attachments/assets/3d9031ed-b1ec-40d5-8c13-c77fe7c82465"
/>
Co-authored-by: Francesco Lodolo [:flod] <flod+pontoon@mozilla.com> (it)
Co-authored-by: Théo Chevalier <theo@theochevalier.org> (fr)
Co-authored-by: Mark Heijl <markh@babelzilla.org> (nl)
Co-authored-by: Michael Köhler <michael.koehler1@gmx.de> (de)
Co-authored-by: Fjoerfoks <fryskefirefox@gmail.com> (fy-NL)
Co-authored-by: Ian Neal <iann_bugzilla@blueyonder.co.uk> (en-GB)
Co-authored-by: Pin-guang Chen <petercpg@mail.moztw.org> (zh-TW)
Co-authored-by: Luna Jernberg <bittin@cafe8bitar.se> (sv-SE)
Co-authored-by: Melo46 <melo@carmu.com> (ia)
Co-authored-by: Valery Ledovskoy <valery@ledovskoy.com> (ru)
Co-authored-by: Jim Spentzos <jimspentzos2000@gmail.com> (el)
When we add the function list, we'll want to be able to sort the table
by either the self column or the total column.
For that use case it makes sense to have separate methods to query these
values.

Functionally neutral change.
…splitters under .DetailsContainer.

For the function list, we'll want to split the "main content" of the
panel into the list on the left and the "wings" on the right, with a
splitter. But this splitter should look like a normal splitter, not
like the extra thick sidebar splitter. But these sidebar splitter
rules were applying to all splitters under .DetailsContainer; this
reduces the scope to only apply to the actual sidebar splitter.
The function handleCallNodeTransformShortcut takes a call node index
as a parameter, but it was getting the call node info separately from
a selector. At the moment that's fine because this is always the right
call node info.

But once we add separate call node infos for things like "the callees
of the selected function in the function list", the two might get out
of sync, so it's better to pass the correct call node info that is
compatible with the passed call node index.

Functionally-neutral change.
This shortcut key is advertised by the context menu but
I forgot to actually implement it.
mstange and others added 27 commits June 23, 2026 09:04
When we add the function list, we'll want to be able to sort the table
by either the self column or the total column.
For that use case it makes sense to have separate methods to query these
values.

Functionally neutral change.
…splitters under .DetailsContainer (#6114)

For the function list, we'll want to split the "main content" of the
panel into the list on the left and the "wings" on the right, with a
splitter. But this splitter should look like a normal splitter, not like
the extra thick sidebar splitter. But these sidebar splitter rules were
applying to all splitters under .DetailsContainer; this reduces the
scope to only apply to the actual sidebar splitter.
The function handleCallNodeTransformShortcut takes a call node index as
a parameter, but it was getting the call node info separately from a
selector. At the moment that's fine because this is always the right
call node info.

But once we add separate call node infos for things like "the callees of
the selected function in the function list", the two might get out of
sync, so it's better to pass the correct call node info that is
compatible with the passed call node index.

Functionally-neutral change.
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: fatadel <afatkhutdinov@mozilla.com>
This will let us use them from other tree views, like the planned
function list tree view.
This will let us use them from other tree views, like the planned
function list tree view.
Co-authored-by: ravmn <ravmn@ravmn.cl> (es-CL)
When a marker stayed selected, its sticky tooltip rendered on top of the
Re-upload and other top-bar menu panels, covering them and intercepting
clicks.

The panels already carry a higher z-index than tooltips (--z-arrow-panel
above --z-tooltip), but .profileViewer set z-index: 0, creating a
stacking context that trapped the panels at its own altitude. Tooltips
render in the body-level #root-overlay layer, which paints later, so
they always won regardless of the scale. Removing that z-index lets the
panels and tooltips share the root stacking context, where the scale
orders them correctly.

Closes #6102
…ation is requested (#6127)

This was a regression from #6018.

Previously, we didn't have a content column in the sources table. But we
now added it, and they are filled automatically during the source map
resolution. We would like to add a sharing feature soon, but this needs
to be an explicit approval. Due to the early return in this
`sanitizePII` function, we were mistakenly keeping these content values
if we hit the early return (if the user wants to sanitize nothing). But
even if the user wants to upload everything, we should unconditionally
sanitize the sources.
Co-authored-by: Fabio Tomat <dark.tmtfx@gmail.com> (fur)
This lets us build the timing rows lazily, as the flame graph
scrolls them into view.

Building the rows isn't that expensive with the regular flame
graph, but it'll be more expensive for the inverted "calls to
the selected function" icicle flame graph that I'm planning to
add to the function list panel.
This takes advantage of the fact that the flame graph now requests
a row only once it's on the screen.

Note that there's a difference between "FlameGraphRows" and
"FlameGraphTiming" rows.
The FlameGraphRows are still computed eagerly. It's just the timing
that is now computed lazily per displayed row.
The FlameGraphRows are based on the call node info and independent of
sample counts and preview selection.

When switching to the Flame Graph panel on https://share.firefox.dev/4g4xGue ,
with a flame graph canvas height of 564px, I'm getting the following
profiles:
Before: https://share.firefox.dev/4w2QEG3 (410ms tab switch)
After: https://share.firefox.dev/3QYB7IA (272ms tab switch)

In those profiles you can also see the different memory usage characteristics.
Before this PR, we were always computing positioning information for the
entire flame graph, even though the viewport is usually too small to
display the entire flame graph - only the N root-most rows are
displayed, until the user starts scrolling / panning. This PR changes it
so that we only compute the box positions / "FlameGraphTiming" for the
rows that get rendered by the flame graph canvas. This speeds up the
initial render of the flame graph panel.

When switching to the Flame Graph panel on
https://share.firefox.dev/4g4xGue , with a flame graph canvas height of
564px, I'm getting the following profiles:

Before: https://share.firefox.dev/4w2QEG3 (410ms tab switch)
After: https://share.firefox.dev/3QYB7IA (272ms tab switch)
This will let us use flame graphs in other places, for example in the
function list panel (for callee / caller views) or in a benchmark
comparison view.

ConnectedFlameGraph is the connected version and works as before.

This commit also removes MaybeFlameGraph. The flame graph no longer respects
the global "is inverted" flag, so the performance warning in MaybeFlameGraph
was never shown. The only other functionality of MaybeFlameGraph was that it
displayed "empty reasons" when the preview selection was empty; this part
has been subsumed into ConnectedFlameGraph.
This will let us use flame graphs in other places, for example in the
function list panel (for callee / caller views) or in a benchmark
comparison view.

ConnectedFlameGraph is the connected version and works as before.

This commit also removes MaybeFlameGraph. The flame graph no longer
respects the global "is inverted" flag, so the performance warning in
MaybeFlameGraph was never shown. The only other functionality of
MaybeFlameGraph was that it displayed "empty reasons" when the preview
selection was empty; this part has been subsumed into
ConnectedFlameGraph.
Updated locales: de, el, en-GB, es-CL, fr, fur, fy-NL, ia, it, nl, ru,
sv-SE, zh-TW.
@canova canova requested review from a team and fatadel as code owners June 29, 2026 09:22
@canova canova merged commit dc29e41 into production Jun 29, 2026
38 checks passed
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.

4 participants