You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Significant slowdown of createContext and runInContext #29842
constvm=require('vm')constctxFn=newvm.Script(` var b = Math.random(); var c = a + b;`);functionrun(m){constctx={a: 'a'};vm.createContext(ctx);for(leti=0;i<m;i++){ctxFn.runInContext(ctx);}}functiontest(n,m){consts=Date.now();for(leti=0;i<m;i++){run(m);}console.log(Date.now()-s);}test(1000,10);
Are you sure you're testing what you think you're testing? n is never used in test().
'use strict';constcommon=require('../common.js');constbench=common.createBenchmark(main,{n: [100]});constvm=require('vm');constctxFn=newvm.Script(` var b = Math.random(); var c = a + b;`);functionmain({ n }){bench.start();letcontext;for(vari=0;i<n;i++){context=vm.createContext({a: 'a'});}bench.end(n);ctxFn.runInContext(context);}
There is a -75.07% performance regression on master with --without-node-snapshot, and the result is similar from comparison between v12.5.0 (with the embedded snapshot) and v10.16.0
I realized that we cannot actually deserialize the default context from the snapshot if the user uses the sandbox argument of vm.createContext, since the context would be different from the one we have for our own Node.js instances. We could still do this for contexts created without the sandbox argument and the users can work around the limitation by setting up the sandbox though property setters after the call to vm.createContext, though.
Hmm, or maybe we could include one more context with the interceptors in the embedded snapshot (however we have to register the interceptors as external references first), and use it in ContextifyContext::CreateV8Context. Then fix up the context object's Symbol.toStringTag property and set up the embedded data slot.
This is also locking up the event loop in version 12. Any more info on the availability of a configure-time flag until this is fixed? Or is the only option to revert to Node 8/10? Thanks
It seems rather difficult to make a toggle for the primordials at configure-time at this point, but another idea would be to lazily initialize the primoridals only when they are necessary for vm contexts - in most cases, there should be no need because it's used by builtin modules that probably will have their own set of primordials when being passed into a context. I am still looking into whether this is safe to do - it does impose some requirements for cross-context support of builtins (e.g. worker_threads.moveMessagePortToContext()) which @addaleax is working on.
Activity
bnoordhuis commentedon Oct 4, 2019
Reproducing here for posterity:
Are you sure you're testing what you think you're testing?
nis never used intest().joyeecheung commentedon Oct 4, 2019
This is what I get from our vm benchmarks using
The slowdown may come from createContext instead
joyeecheung commentedon Oct 4, 2019
I tried with this benchmark
There is a -75.07% performance regression on master with
--without-node-snapshot, and the result is similar from comparison between v12.5.0 (with the embedded snapshot) and v10.16.0benchmark: add benchmark for vm.createContext
joyeecheung commentedon Oct 10, 2019
I proflied the benchmark (stripped out into a separate script).
Output of --prof:
And of
--cpu-profI suspect this is related to #29766 - one possibility is to make primordials behind a configure-time flag until we fix the performance issues.
joyeecheung commentedon Oct 11, 2019
Oh, wait, I realized that the screenshot in #29842 (comment) should not contain frames of
primordials.jsat all - these can be deserialized instead.benchmark: add benchmark for vm.createContext
joyeecheung commentedon Jan 6, 2020
Reposted from #29925
joyeecheung commentedon Jan 6, 2020
Hmm, or maybe we could include one more context with the interceptors in the embedded snapshot (however we have to register the interceptors as external references first), and use it in
ContextifyContext::CreateV8Context. Then fix up the context object'sSymbol.toStringTagproperty and set up the embedded data slot.spasam commentedon Feb 10, 2020
This is also locking up the event loop in version 12. Any more info on the availability of a configure-time flag until this is fixed? Or is the only option to revert to Node 8/10? Thanks
joyeecheung commentedon Feb 11, 2020
It seems rather difficult to make a toggle for the primordials at configure-time at this point, but another idea would be to lazily initialize the primoridals only when they are necessary for vm contexts - in most cases, there should be no need because it's used by builtin modules that probably will have their own set of primordials when being passed into a context. I am still looking into whether this is safe to do - it does impose some requirements for cross-context support of builtins (e.g.
worker_threads.moveMessagePortToContext()) which @addaleax is working on.vm: lazily initialize primordials for vm contexts
vm: lazily initialize primordials for vm contexts
vm: lazily initialize primordials for vm contexts
vm: lazily initialize primordials for vm contexts