Sitelet https://github.com/nodejs/node/issues/9473
Skip to content

Research Discussion: Faster startup with dynamically generated custom v8 snapshots #9473

Description

If you know about v8 snapshots, and node's 'default' snapshot, you might be able to provide insight into this discussion.

I seem to be using more and more 'commands' that are node based. When I run them, like npm, it's my understanding node has to reload and recompile the entry.js and all its require()d modules every time.

I'm wondering if just before node exited, if it could take a v8 snap and save it to a file named to correlate to the full path of entry.js. (obviously optimized to only snap when something changed however, so not every time node exited)

Then, when node was launched again, it could look for a saved snap based on entry.js and just create a new context from that snap, effectively getting to an executing state much faster.

At a high level I'm wondering if my understanding is correct, that a v8 snap is a heap dump that can be reloaded into an isolate, and that when a new context is created in the isolate it starts with modules already jitted, having come from the snap. But wouldn't there be some state that was 'left over' from the original snap that could potentially 'infect' the new context in some non deterministic way? Like say a module set a flag within itself, then the snap was taken, then when reloaded the flag would still be set?

Is there even a possibility, in some way, to save something from run to run, such that entry.js and all require()'d modules don't have to be parsed/jitted every time?

Activity

  1. mscdex commented on Nov 5, 2016

    @mscdex
    Contributor

    Well, vm already has a way to produce/use binary code cache data. Is that what you're after or ?

  2. added
    questionIssues asking questions about Node.js.
    feature requestIssues requesting new Node.js features.
    and removed
    questionIssues asking questions about Node.js.
    on Nov 5, 2016
  3. mscdex commented on Nov 5, 2016

    @mscdex
    Contributor

    @phestermcs It's probably not a V8 snapshot proper. The vm options I was referring to specifically were cachedData and produceCachedData. Also, see this V8 blog post about it.

  4. ghost changed the title [-]Discussion: Faster startup with auto custom v8 snapshots[/-] [+]Discussion: Faster startup with dynamically generated custom v8 snapshots[/+] on Nov 5, 2016
  5. bnoordhuis commented on Nov 5, 2016

    @bnoordhuis
    Member

    At a high level I'm wondering if my understanding is correct, that a v8 snap is a heap dump that can be reloaded into an isolate, and that when a new context is created in the isolate it starts with modules already jitted, having come from the snap.

    That's correct. A snapshot is essentially the serialized state of the process at the time the snapshot was taken. It's a bit like emacs's unexec or sbcl's save-lisp-and-die command.

    cachedData does something different, it's just a precompile step. It takes source code and compiles it into baseline machine code but it doesn't optimize or run it. Unless you are on a slow system (like raspberry pi 1 slow), the overhead of the baseline compiler is negligible for most applications.

    The problem with snapshots is that there is no way to revive external state, like file descriptors, child processes, etc. That makes it useless for quickstarting most applications.

  6. ghost changed the title [-]Discussion: Faster startup with dynamically generated custom v8 snapshots[/-] [+]Resarch Discussion: Faster startup with dynamically generated custom v8 snapshots[/+] on Nov 6, 2016
  7. ghost changed the title [-]Resarch Discussion: Faster startup with dynamically generated custom v8 snapshots[/-] [+]Research Discussion: Faster startup with dynamically generated custom v8 snapshots[/+] on Nov 6, 2016
  8. bnoordhuis commented on Nov 7, 2016

    @bnoordhuis
    Member

    The embedder - i.e., node.js - can register FunctionTemplates and ObjectTemplates when the snapshot is created. There is probably no way to make that work for native add-ons, though.

    Hard to say whether it's going to be significantly faster on average. Taking a snapshot right after start-up won't help much if your application doesn't do significant processing at start-up. Most of the main application will still be baseline code (or won't have been compiled at all if lazy compilation is enabled) because it hasn't run long enough to reach the optimizing tier.

  9. bnoordhuis commented on Nov 8, 2016

    @bnoordhuis
    Member

    Regarding Templates, I'm thinking registering them wouldn't be a problem, rather having an instance of them in the heap, that was still referenced, would be the problem; when the snap would be deserialized in a new isolate, those instances would be pointing to who knows what.

    If I understand your concern correctly: there is a mechanism for saving and restoring FunctionTemplate function pointers and a similar (albeit not identical) mechanism for internal fields.

    (Untested but I suspect there are actually several ways to restore function pointers. One is Isolate::CreateParams::external_references, another is FunctionTemplate::FromSnapshot() followed by FunctionTemplate::SetCallHandler().)

    what is the difference in performance between just baseline compiled code vs. having been fully optimized as much as possible?

    I'd say 1.5-2x on average. If you want to try it out, --nocrankshaft disables the optimizing tier.

    I can't help but kinda 'know' there's just no way that going from utf8 text across thousands of files, to a single chunk of optimized code, is done so fast that it shouldn't matter.

    I wouldn't say it's so fast it never matters but the baseline compiler is really just a template JIT: it's not smart at all, it's just fast (but not fast enough on mobile systems, hence the Ignition interpreter that is being added.)

    Lazy compilation is another factor (and is enabled by default): generating machine code for a function doesn't happen until the first time it's called.

  10. ghost closed this as completedon Nov 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussIssues opened for discussion and feedback.feature requestIssues requesting new Node.js features.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions