Repository navigation
RFC: speeding up Node.js startup using V8 snapshot #17058
Description
Activity
- addeddiscussIssues opened for discussion and feedback.Issues opened for discussion and feedback.feature requestIssues requesting new Node.js features.Issues requesting new Node.js features.help wantedIssues that need assistance from volunteers or PRs that need help to proceed.Issues that need assistance from volunteers or PRs that need help to proceed.v8 engineIssues and PRs related to the V8 dependency.Issues and PRs related to the V8 dependency.
on Nov 15, 2017 - addedperformanceIssues and PRs related to the performance of Node.js.Issues and PRs related to the performance of Node.js.
on Nov 15, 2017 Sounds great. Is there a repo/branch people can take a look at the changes you have so far for this work ?
I have a development branch here. All tests still pass, because they are not affected. Running
node snapshotattempts to create a snapshot blob. It currently still fails, but I have collected almost all native references. There is still a long way to go though.Hi @hashseed, this is amazing and very needed, thanks for working on this. I asked on #17103 but it seems pertinent to this thread (since it's an RFC) so I'll ask here as well.
Would these changes allow for taking snapshots in arbitrary points in time? as opposed to right after startup? If not, do you mind explaining if such a thing would even be feasible. Seems like the guys from Chakra have been working on something like it for Time Travel Debugging (as mentioned by @mrkmarron: #13877 (comment))
To elaborate a little, I'm thinking something like CRIU, where you can send a signal to the process (e.g.
kill -USR2 <pid>or some other mechanism) and have the process serialize it's state (to a predefined location maybe) and optionally exit. Then later in time you could restore that serialized state by providing it to a new node process (e.g.node --restore <state-file>)Reacted by Hermann Rolfes and ThisRabbitIt would, once finished, help achieve that goal. Current V8 API is not laid out to serialize arbitrary isolates at arbitrary times, but something in that direction would be thinkable.
However, there are quite a few C++ objects allocated by native modules. Each module would have to provide a way to serialize/deserialize its objects, and we would need a way to dispatch to each module for serialization/deserialization. This hurdle applies to Node with Chakra too.
Another issue is that there is no good way to serialize/deserialize the stack, including C++ frames and local variables that hold onto objects on the JS heap.
Reacted by Juan Campa, Ivan, Horaddrim, Jiri Spac and Hermann RolfesHi @hashseed, I was able to take a quick look at the document and the commits. As you say it looks like there is a lot of work left but this looks like a great start. Please let me know if there is anything that might be useful to help and I will try to make some time. Otherwise, I'll definitely keep an eye on the progress here.
Thanks for this effort!
Hi Mark,
this is more of a solve-issues-as-we-go approach. Once I have a roughly working version done, there will be some more careful auditing necessary to see which part of initialization needs to be done after snapshotting because they are runtime-dependent, for example gated by command line args. Maybe that's something you can dig into, if you have the time?
Sure, I have looked into this type of thing in the past. The two most common approaches seem to be either (1) making this type of startup a pure programmer responsibility or (2) using symbolic execution (ala prepack). Neither solution is 100% satisfactory but I'll try to spend some time investigating to get a better understanding of things.
I updated the branch. So far running
node snapshotcreates asnapshot_blob.binfile into the working directory. With the file in place, runningnodeuses the snapshot, deserializes an isolate and a context, and then immediately quits (because I haven't spent time on making the deserialized context work yet :D).For some reason I wasn't able to reproduce the 400ms start up for vanilla Node.js anymore, but rather 200ms. I wonder whether I made some mistake with the build. But when I instrumented my branch with
uv_hrtime()I was at least able to reproduce 4x speed up.I'll carry on to make the deserialized context actually work.
@addaleax @bnoordhuis @TimothyGu is there any reason we store the environment in a v8::External object to pass to function templates as data, instead of getting the current context from the isolate and the environment from there?
v8::Externalsare tricky to serialize. They should belong to the context. Function and object templates belong to the isolate, but can ownv8::Externalobjects as data. With the current API there is no good way serialize templates as part of the context.v8::Externalobjects are also kinda hacky. They look like JavaScript objects, but are special in that they are context-independent and don't have a constructor.94 remaining items
- added 3 commits that reference this issue
on Jun 30, 2020 - added a commit that references this issue
on Jul 4, 2020 - added 4 commits that reference this issue
on Jul 13, 2020 - added 2 commits that reference this issue
on Jul 16, 2020 Since the core bootstrap is now in the builtin snapshot, and we are working towards including more of the bootstrap into the snapshot, maybe it's time to close this and open a new tracking issue?
Reacted by Juan JoséSince the core bootstrap is now in the builtin snapshot, and we are working towards including more of the bootstrap into the snapshot, maybe it's time to close this and open a new tracking issue?
LGTM.
Opened #35711 for discussions around future snapshot work.
I recently went through Node.js bootstrapping code, and think that we could make it a lot faster using V8 snapshot. I wrote a design doc that captures the main points.
This is somewhat separate from the discussion on using V8 snapshot to capture arbitrary initialized state, discussed here. The main difference is that the set of native modules is known upfront, and there is no ambiguity about the native bindings that need to be known to V8's serializer/deserializer.
I'm doing this as sort of a side project, so it may take some time for me to make progress. Any help is welcome.