mstange · GitHub

We'll want to add a binary serialization soon, but we'll also
keep the JSON serializatios as an option. This rename makes it
clear which one you're calling.

@mstange

Fixes firefox-devtools#6024.
JsonSlabs is an alternative serialization format that's more
efficient than JSON if the serialized object contains typed arrays.
See https://github.com/mstange/json-slabs/ for details.
Our profiles currently do not yet contain typed arrays. But with this
in place, we can start converting more and more tables / columns to
use typed arrays, and incrementally reap the efficiency benefits.
This patch only adds the reading. In the UI, uploading / downloading
profiles still uses JSON.
For the profiler-edit node script, this patch also adds the "writing":
If you run profiler-edit with `-o some-filename-ending-in.jslb`, then
it will create a JSLB file (or a compressed JSLB file for .jslb.gz).
---
The profile format "structure" is still the same as before. The format
version is still given by profile.meta.preprocessedProfileVersion.
Loading a JSLB file with a profile.meta.preprocessedProfileVersion that's
higher than the currently known one will still complain, and attempt to
reload the page or the service worker.
This reload behavior is the primary reason why I want to get the
"reading" part taken care of first, before we start converting any
parts of the profile to get efficiency wins: The sooner we land this,
the more likely it will be that, in the future, if somebody has a newer
JSLB file but an old cached profiler, they'll see a useful error and
get the auto-reload.
Without this patch, loading a JSLB file in the profiler gives the
following error:
> Error: Unserializing the profile failed: Error: The profile array
> buffer could not be parsed as a UTF-8 string.
---
With all that said, it turns out there is already a case where this
format gives an efficiency win, thanks to its "split out" feature
that lets us put certain subtrees of the profile into separate JSON
slabs: If the original JSON is larger 512MiB, we can split it into
individual slabs which are each smaller than 512MiB, so the built-in
JSON.parse will work and we don't have to use the slow streaming parse.
Example:
https://storage.googleapis.com/profiler-get-symbols-fixtures/large-speedometer3-profile.json.gz
expands to a 577.74MB JSON file,
https://storage.googleapis.com/profiler-get-symbols-fixtures/large-speedometer3-profile.jslb.gz
expands to a 564.66MB JSLB file (slightly smaller because compacting removed unused strings)
The JSLB file breaks down as follows:
```
idx  type          bytes  elements  path
---  -------  ----------  --------  -------------------
  0  json      16.76 MiB         -  .                    (root)
  1  json     264.82 MiB         -  .shared.stackTable
  2  json      91.01 MiB         -  .shared.frameTable
  3  json       8.47 MiB         -  .shared.funcTable
  4  json      28.80 MiB         -  .shared.stringArray
  5  json     154.80 MiB         -  .threads
---  -------  ----------  --------  -------------------
     6 slabs  564.66 MiB
```
All of those individual JSON slabs are now under 512MiB.
Loading the JSON file, uses streaming parser: https://share.firefox.dev/3PcB9vK (19 seconds)
Loading the JSLB file, uses native JSON.parse: https://share.firefox.dev/3RkFcXs (2.3 seconds, 8.3x faster)

@mstange

@mstange

@mstange

@mstange

Merged

canova added a commit that referenced this pull request

Jun 16, 2026
Changes:
[Nazım Can Altınova] Fix call node context menu being hidden behind
source view bottom box (#6045)
[Nazım Can Altınova] Pass `--use-env-proxy` only when the node version
is >= 24 (#6064)
[fatadel] Upgrade @firefox-devtools/react-contextmenu to 5.2.4 (#6066)
[Markus Stange] Switch profiler-edit from minimist to commander (#6065)
[Markus Stange] Support reading profiles from JsonSlabs files (#6037)
[Florian Quèze] Don't fail profile processing when a marker's stack
field is not a backtrace (#6069)
[fatadel] Replace the footer-links overlay with a settings menu (#6042)
[fatadel] Upgrade @types/node to match Node 24 (#6070)
[fatadel] Remove unused undici-types package (#6074)
[cathaysia] Update isLocalURL to include LAN addresses, .local domains,
and hostn… (#5973)
[Markus Stange] Fix from-url with binary profiles (#6072)
[fatadel] Upgrade to React 19 (#6067)
[Markus Stange] Add an insertStackLabels helper. (#6076)
[fatadel] Drive counter tooltips from a tooltipRows schema (#6023)
[fatadel] Add TrackPower--tooltip-average-power-microwatt (#6080)
[Markus Stange] Downgrade to React 19.1 to fix unusable dev build
performance. (#6082)
[Nazım Can Altınova] Add source map symbolication and source view
support (#6018)
[spokodev] fix(FilterNavigatorBar): clip overflow so many breadcrumbs do
not expand the parent (#6085)
[Markus Stange] Move paddings inside the tree header cells. (#6002)
[Markus Stange] Add an --insert-label-frames argument to the
profiler-edit tool (#5966)
[Markus Stange] Stop printing "error: too many arguments" during tests.
(#6088)
[Markus Stange] More additions to profiler-edit, for sp3 profiles
(#6009)
[Nazım Can Altınova] Do not rely on localized texts in the settings menu
tests (#6101)
And special thanks to our localizers:
be: Andrei Mukamolau
de: Ger
de: Michael Köhler
de: Ralf Duehnfahr
el: Jim Spentzos
en-CA: chutten
en-GB: Ian Neal
es-CL: ravmn
fr: Théo Chevalier
fr: wy
fur: Fabio Tomat
fy-NL: Fjoerfoks
ia: Melo46
it: Francesco Lodolo [:flod]
nl: Mark Heijl
ru: Valery Ledovskoy
sr: Марко Костић (Marko Kostić)
sv-SE: Andreas Pettersson
tr: Grk
tr: Selim Şumlu
zh-CN: Olvcpr423
zh-TW: Pin-guang Chen

Read the original on github.com ↗