Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sea: snapshot support in single executable applications #46824

Merged
merged 4 commits into from
Jul 20, 2023

Conversation

joyeecheung
Copy link
Member

@joyeecheung joyeecheung commented Feb 24, 2023

Refs: nodejs/single-executable#57

This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add "useSnapshot": true to the configuration passed to
--experimental-sea-config. For example:

{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}

The main script used to build the snapshot must invoke
v8.startupSnapshot.setDeserializeMainFunction() to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the main script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

$ /path/to/node --experimental-sea-config sea-config.json
$ cp /path/to/node sea
$ postject sea NODE_SEA_BLOB sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
$ ./sea

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/startup

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Feb 24, 2023
@RaisinTen
Copy link
Contributor

Thanks for doing this!

add some tooling to process the inputs

I personally really like this approach. I've opened a discussion in nodejs/single-executable#58, so that we can have a decision on this.

@RaisinTen RaisinTen added the single-executable Issues and PRs related to single-executable applications label May 12, 2023
@joyeecheung joyeecheung changed the title POC: snapshot support in single executable applications sea: snapshot support in single executable applications Jun 10, 2023
@joyeecheung
Copy link
Member Author

Rebased using the new SnapshotBuilder::Generate() overload added in #48242 and added a test. Will add more doc and tests next week but the implementation is there.

@piranna
Copy link
Contributor

piranna commented Jun 11, 2023

Rebased using the new SnapshotBuilder::Generate() overload added in #48242 and added a test. Will add more doc and tests next week but the implementation is there.

What's the difference between snapshot and code cache (bytenode)?

@nodejs-github-bot

This comment was marked as outdated.

@joyeecheung
Copy link
Member Author

joyeecheung commented Jun 14, 2023

What's the difference between snapshot and code cache (bytenode)?

If you have a bunch of top level code with a bunch of inner functions, usually when building the snapshot you run all the top level code and compile some of the inner functions, the snapshot contains the state of the heap after the top-level code is run and the bytecode of the inner functions that would be run again later. When deserializing the snapshot, you deserialize the state of an initialized heap (so there is no need to run the top-level code at all), and maybe later when the application invokes some of the inner functions, V8 deserialize the bytecode in the snapshot during the compilation of the function to speed things up. If there's just the code cache, what usually happens is that you have the bytecode of the top-level code and some inner functions. At runtime V8 deserializes the bytecode in the code cache to speed up compilation of the top-level code, but it still needs to run the top-level code to set up the heap.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot
Copy link
Collaborator

@joyeecheung joyeecheung marked this pull request as ready for review June 14, 2023 15:22
@joyeecheung
Copy link
Member Author

CI is almost green (with some flakes that look irrelevant). Can I have some reviews please? @nodejs/single-executable thanks!

@piranna
Copy link
Contributor

piranna commented Jun 14, 2023

If you have a bunch of top level code with a bunch of inner functions, usually when building the snapshot you run all the top level code and compile some of the inner functions, the snapshot contains the state of the heap after the top-level code is run and the bytecode of the inner functions that would be run again later. When deserializing the snapshot, you deserialize the state of an initialized heap (so there is no need to run the top-level code at all), and maybe later when the application invokes some of the inner functions, V8 deserialize the bytecode in the snapshot during the compilation of the function to speed things up. If there's just the code cache, what usually happens is that you have the bytecode of the top-level code and some inner functions. At runtime V8 deserializes the bytecode in the code cache to speed up compilation of the top-level code, but it still needs to run the top-level code to set up the heap.

Thank you @joyeecheung for your detailed explain :-) So, if I understood it correctly, a snapshoot is a combo of a module compiled and bytecode functions plus heap after executing the module top level code, while the code cache only have the bytecode of all the module code, isn't it?

@joyeecheung
Copy link
Member Author

So, if I understood it correctly, a snapshoot is a combo of a module compiled and bytecode functions plus heap after executing the module top level code, while the code cache only have the bytecode of all the module code, isn't it?

Roughly yes. V8 does not always emit bytecode for all the code it encounters (e.g. inner-inner functions are usually just parsed for syntax checks, but no bytecode is generated until they actually get executed). In some cases snapshots may contain more bytecode if during the snapshot building cases these functions are invoked.

@piranna
Copy link
Contributor

piranna commented Jun 15, 2023

V8 does not always emit bytecode for all the code it encounters

Maybe bytenode is forcing its generation? Could it of our interest when generating the snapshots, so no Javascript code is included in it?

Copy link
Member

@benjamingr benjamingr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@benjamingr
Copy link
Member

@RaisenTen can you please confirm you are comfortable with this based on nodejs/single-executable#58 and nodejs/single-executable#58 (reply in thread) landing

@joyeecheung
Copy link
Member Author

joyeecheung commented Jun 15, 2023

Could it of our interest when generating the snapshots, so no Javascript code is included in it?

I would say that's not always a win, you could also have a lot of dead code in that application, or code that never gets run in many use cases, then eagerly generating code may result in a memory/size overhead that's not always worth it. As a configurable thing that might be useful though.

@RaisinTen
Copy link
Contributor

I can try to take a look day after tomorrow. (I'll be traveling pretty much the entire day tomorrow)

@piranna
Copy link
Contributor

piranna commented Jun 15, 2023

As a configurable thing that might be useful though.

Agree on that 👍🏻

@nodejs-github-bot
Copy link
Collaborator

@joyeecheung joyeecheung added commit-queue Add this label to land a pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. labels Jul 20, 2023
@nodejs-github-bot nodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Jul 20, 2023
@nodejs-github-bot
Copy link
Collaborator

Commit Queue failed
- Loading data for nodejs/node/pull/46824
✔  Done loading data for nodejs/node/pull/46824
----------------------------------- PR info ------------------------------------
Title      sea: snapshot support in single executable applications (#46824)
Author     Joyee Cheung  (@joyeecheung)
Branch     joyeecheung:sea-snapshot -> nodejs:main
Labels     c++, lib / src, needs-ci, commit-queue-squash, single-executable
Commits    4
 - src: support snapshot in single executable applications
 - fixup! src: support snapshot in single executable applications
 - fixup! fixup! src: support snapshot in single executable applications
 - fixup! fixup! fixup! src: support snapshot in single executable appli…
Committers 1
 - Joyee Cheung 
PR-URL: https://github.com/nodejs/node/pull/46824
Refs: https://github.com/nodejs/single-executable/discussions/57
Reviewed-By: Benjamin Gruenbaum 
Reviewed-By: Darshan Sen 
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/46824
Refs: https://github.com/nodejs/single-executable/discussions/57
Reviewed-By: Benjamin Gruenbaum 
Reviewed-By: Darshan Sen 
--------------------------------------------------------------------------------
   ℹ  This PR was created on Fri, 24 Feb 2023 18:28:13 GMT
   ✔  Approvals: 2
   ✔  - Benjamin Gruenbaum (@benjamingr) (TSC): https://github.com/nodejs/node/pull/46824#pullrequestreview-1482036842
   ✔  - Darshan Sen (@RaisinTen) (TSC): https://github.com/nodejs/node/pull/46824#pullrequestreview-1538950503
   ✘  Last GitHub CI failed
   ℹ  Last Full PR CI on 2023-07-20T18:44:40Z: https://ci.nodejs.org/job/node-test-pull-request/52874/
- Querying data for job/node-test-pull-request/52874/
   ✔  Last Jenkins CI successful
--------------------------------------------------------------------------------
   ✔  Aborted `git node land` session in /home/runner/work/node/node/.ncu
https://github.com/nodejs/node/actions/runs/5615590467

@joyeecheung joyeecheung added commit-queue Add this label to land a pull request using GitHub Actions. and removed commit-queue-failed An error occurred while landing this pull request using GitHub Actions. labels Jul 20, 2023
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Jul 20, 2023
@nodejs-github-bot nodejs-github-bot merged commit ac34e75 into nodejs:main Jul 20, 2023
@nodejs-github-bot
Copy link
Collaborator

Landed in ac34e75

### Startup snapshot support

The `useSnapshot` field can be used to enable startup snapshot support. In this
case the `main` script would not be when the final executable is launched.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing a run: "would not be run"

rluvaton pushed a commit to rluvaton/node that referenced this pull request Jul 21, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
pluris pushed a commit to pluris/node that referenced this pull request Aug 6, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
pluris pushed a commit to pluris/node that referenced this pull request Aug 7, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
Ceres6 pushed a commit to Ceres6/node that referenced this pull request Aug 14, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
UlisesGascon pushed a commit to UlisesGascon/node that referenced this pull request Aug 14, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: nodejs#46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
RafaelGSS pushed a commit that referenced this pull request Aug 15, 2023
This patch adds snapshot support to single executable applications.
To build a snapshot from the main script when preparing the
blob that will be injected into the single executable application,
add `"useSnapshot": true` to the configuration passed to
`--experimental-sea-config`. For example:

```
{
    "main": "snapshot.js",
    "output": "sea-prep.blob",
    "useSnapshot": true
}
```

The main script used to build the snapshot must invoke
`v8.startupSnapshot.setDeserializeMainFunction()` to configure the
entry point. The generated startup snapshot would be part of the
preparation blob and get injected into the final executable.

When the single executable application is launched, instead of running
the `main` script from scratch, Node.js would instead deserialize the
snapshot to get to the state initialized during build-time directly.

PR-URL: #46824
Refs: nodejs/single-executable#57
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Darshan Sen <[email protected]>
@UlisesGascon UlisesGascon mentioned this pull request Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. single-executable Issues and PRs related to single-executable applications
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants