Skip to content

Conversation

@karlseguin
Copy link
Collaborator

@karlseguin karlseguin commented Dec 18, 2025

There are two layers here. The first is that, on startup, a v8 SnapshotCreator is created, and a snapshot-specific isolate/context is setup with our browser environment. This contains most of what was in Env.init and a good chunk of what was in ExecutionWorld.createContext. From this, we create a v8.StartupData which is used for the creation of all subsequent contexts. The snapshot sits at the application level, above the Env - it's re-used for all envs/isolates, so this gives a nice performance boost for both 1 connection opening multiple pages or multiple connections opening 1 page.

The second layer is that the Snapshot data can be embedded into the binary, so that it doesn't have to be created on startup, but rather created at build-time. This improves the startup time (though, I'm not really sure how to measure that accurately...).

The first layer is the big win (and just works as-is without any build / usage changes).

with snapshot
total runs 1000
total duration (ms) 7527
avg run duration (ms) 7
min run duration (ms) 5
max run duration (ms) 41

without snapshot
total runs 1000
total duration (ms) 9350
avg run duration (ms) 9
min run duration (ms) 8
max run duration (ms) 42

To embed a snapshot into the binary, we first need to create the snapshot file:

zig build -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin

And then build using the new snapshot_path argument:

zig build -Dsnapshot_path=../../snapshot.bin -Doptimize=ReleaseFast

The paths are weird, I know...since it's embedded, it needs to be inside the project path, hence we put it in src/snapshot.bin. And since it's embedded relative to the embedder (src/browser/js/Snapshot.zig) the path has to be relative to that, hence ../../snapshot.bin. I'm open to suggestions on improving this.

There are two layers here. The first is that, on startup, a v8 SnapshotCreator
is created, and a snapshot-specific isolate/context is setup with our browser
environment. This contains most of what was in Env.init and a good chunk of
what was in ExecutionWorld.createContext. From this, we create a v8.StartupData
which is used for the creation of all subsequent contexts. The snapshot sits
at the application level, above the Env - it's re-used for all envs/isolates, so
this gives a nice performance boost for both 1 connection opening multiple pages
or multiple connections opening 1 page.

The second layer is that the Snapshot data can be embedded into the binary, so
that it doesn't have to be created on startup, but rather created at build-time.
This improves the startup time (though, I'm not really sure how to measure that
accurately...).

The first layer is the big win (and just works as-is without any build / usage
changes).

with snapshot
total runs 1000
total duration (ms) 7527
avg run duration (ms) 7
min run duration (ms) 5
max run duration (ms) 41

without snapshot
total runs 1000
total duration (ms) 9350
avg run duration (ms) 9
min run duration (ms) 8
max run duration (ms) 42

To embed a snapshot into the binary, we first need to create the snapshot file:

zig build -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin

And then build using the new snapshot_path argument:

zig build -Dsnapshot_path=../../snapshot.bin -Doptimize=ReleaseFast

The paths are weird, I know...since it's embedded, it needs to be inside the
project path, hence we put it in src/snapshot.bin. And since it's embedded
relative to the embedder (src/browser/js/Snapshot.zig) the path has to be
relative to that, hence ../../snapshot.bin. I'm open to suggestions on
improving this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants