| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Review requested:
|
Sorry, something went wrong.
Codecov Report❌ Patch coverage is 66.66667% with 19 lines in your changes missing coverage. Please review.
@@ Coverage Diff @@
## main #65329 +/- ##
==========================================
- Coverage 90.13% 90.09% -0.05%
==========================================
Files 752 752
Lines 251568 252348 +780
Branches 47270 47462 +192
==========================================
+ Hits 226759 227355 +596
- Misses 16168 16292 +124
- Partials 8641 8701 +60
... and 76 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Sorry, something went wrong.
Sorry, something went wrong.
|
Benchmark GHA (misc / startup-core): https://github.com/nodejs/node/actions/runs/32009241408 Results
Benchmark results: confidence improvement accuracy (*) (**) (***) misc/startup-core.js n=30 mode='process' script='benchmark/fixtures/empty.mjs' 0.95 % ±16.58% ±21.85% ±28.04% misc/startup-core.js n=30 mode='process' script='benchmark/fixtures/import-builtins.mjs' 0.60 % ±11.57% ±15.25% ±19.56% misc/startup-core.js n=30 mode='process' script='benchmark/fixtures/require-builtins.js' 0.19 % ±13.51% ±17.81% ±22.85% misc/startup-core.js n=30 mode='process' script='test/fixtures/semicolon.js' -0.02 % ±16.55% ±21.81% ±27.99% misc/startup-core.js n=30 mode='process' script='test/fixtures/snapshot/typescript.js' -0.54 % ±8.97% ±11.82% ±15.17% misc/startup-core.js n=30 mode='worker' script='benchmark/fixtures/empty.mjs' 3.74 % ±9.02% ±11.89% ±15.26% misc/startup-core.js n=30 mode='worker' script='benchmark/fixtures/import-builtins.mjs' 1.08 % ±8.87% ±11.69% ±15.00% misc/startup-core.js n=30 mode='worker' script='benchmark/fixtures/require-builtins.js' 1.37 % ±8.86% ±11.67% ±14.98% misc/startup-core.js n=30 mode='worker' script='test/fixtures/semicolon.js' 4.08 % ±9.20% ±12.13% ±15.56% misc/startup-core.js n=30 mode='worker' script='test/fixtures/snapshot/typescript.js' -0.84 % ±8.49% ±11.19% ±14.36% Be aware that when doing many comparisons the risk of a false-positive result increases. In this case, there are 10 comparisons, you can thus expect the following amount of false-positive results: 0.50 false positives, when considering a 5% risk acceptance (*, **, ***), 0.10 false positives, when considering a 1% risk acceptance (**, ***), 0.01 false positives, when considering a 0.1% risk acceptance (***)
|
Sorry, something went wrong.
There was a problem hiding this comment.
lgtm
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
|
The modified test is failing on Windows, indicating this PR is adding flakiness. Can you have a look? ---
duration_ms: 293.997
exitcode: 1
severity: fail
stack: |-
node:internal/assert/utils:146
throw error;
^
AssertionError [ERR_ASSERTION]: These builtins are now no longer loaded before pre-execution.
If this is intentional, remove them from `expected.beforePreExec`.
--- These could be removed from expected.beforePreExec ---
[
'Internal Binding cjs_lexer',
'Internal Binding encoding_binding',
'NativeModule internal/blob',
'NativeModule internal/data_url',
'NativeModule internal/dns/utils',
'NativeModule internal/encoding',
'NativeModule internal/encoding/single-byte',
'NativeModule internal/encoding/util',
'NativeModule internal/mime',
'NativeModule internal/modules/esm/assert',
'NativeModule internal/modules/esm/get_format',
'NativeModule internal/modules/esm/load',
'NativeModule internal/modules/esm/loader',
'NativeModule internal/modules/esm/module_job',
'NativeModule internal/modules/esm/module_map',
'NativeModule internal/modules/esm/resolve',
'NativeModule internal/modules/esm/translators',
'NativeModule internal/modules/typescript',
'NativeModule internal/net',
'NativeModule url'
]
These builtins are now unexpectedly loaded at run time.
If this is intentional, add them to `expected.atRunTime`.
# Note: loading more builtins at run time can lead to startup performance regression.
- Consider lazy loading builtins that are not used universally.
--- These could be added to expected.atRunTime ---
[
'NativeModule internal/modules/esm/get_format'
]
12 !== 0
at Object.<anonymous> (d:\workspace\node-test-binary-windows-js-suites\node\test\parallel\test-bootstrap-modules.js:264:8)
at Module._compile (node:internal/modules/cjs/loader:1937:14)
at Module._extensions..js (node:internal/modules/cjs/loader:2077:10)
at Module.load (node:internal/modules/cjs/loader:1659:32)
at Module._load (node:internal/modules/cjs/loader:1451:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:261:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
at node:internal/main/run_main_module:33:47 {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: 12,
expected: 0,
operator: 'strictEqual',
diff: 'simple'
}
Node.js v27.0.0-pre
...
|
Sorry, something went wrong.
|
@aduh95 fixed! |
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
|
I am in favor of "for snapshot less mode, try not to eager load that much" in general, although some of the removals seem somewhat too conservative (e.g. the url and util modules are commonly used by most applications) and may only favor the startup of empty scripts but penalise the startup of a real application that actually does something. So I think we should check the performance impact of the scripts that does something beyond being empty as well. If the number misc/startup-core.js mode='process' (snapshot), all scripts ±0.5 % n.s. Comes from that scenario then LGTM, otherwise can you run the benchmark across the startup-core and startup-cli-version data sets? |
Sorry, something went wrong.
Sorry, something went wrong.
|
@joyeecheung yes, that row is startup-core mode=process with the snapshot, all five scripts including require-builtins.js and import-builtins.mjs; the benchmark CI run above (https://github.com/nodejs/node/actions/runs/32009241408) shows the same on all four machines: process rows within ±1 % n.s., worker rows +1…5 %. for the "app that actually does something" case i ran startup-cli-version and a builtin-heavy entry point both with the snapshot and with --no-node-snapshot (n=30, linux x64): with snapshot --no-node-snapshot
startup-cli-version eslint --version -0.14 % n.s. +1.70 % ***
npm --version -0.00 % n.s. +0.69 % ***
npx --version +0.11 % n.s. +0.80 % **
corepack --version -0.19 % n.s. +3.21 % ***
require-builtins.js (start -> exit) -0.08 % n.s. +1.97 % ***
import-builtins.mjs +0.19 % n.s. +0.13 % n.s.
empty CJS entry +0.04 % n.s. +10.59 % ***
so nothing gets penalized: with the snapshot the preloaded set is unchanged (they sit behind isBuildingSnapshot() rather than being removed), and without it util/url/the esm loader are loaded on first require at the same cost as before, just not up front for entry points that never touch them. the win shrinks as the app uses more of core, as you'd expect, but it doesn't go negative. |
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
Sorry, something went wrong.
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
| Back | FazBrowse Home | New Git URL |
Worker startup gets ~6 % faster and a snapshot-less main-thread bootstrap (embedders that create their own isolate, --no-node-snapshot) ~10 % faster, by not eagerly loading builtins those paths never use. Startup with the snapshot is unchanged.
Builtins compiled: bare worker 95 → 83; --no-node-snapshot empty CJS entry 76 → 59, empty ESM entry 76 → 69.
Contexts that aren't deserialized from the snapshot compile every builtin the bootstrap touches, so each eager require there is startup time (~0.15–0.4 ms apiece). Several are eager only so that they land in the snapshot, or for features the bootstrap doesn't use. This makes them lazy without changing the snapshot's contents:
An intermediate version that didn't re-add these to the snapshot regressed node empty.mjs by 2–4 %, which is why the isBuildingSnapshot() block lists them explicitly. test-bootstrap-modules is adjusted for the worker-side list.
Tests: test-bootstrap-modules plus worker, url, fs, dns, process, cli, vm, snapshot, blob, esm, inspector, module, util, test-runner and single-executable suites pass.
Disclosure: the code, test, measurements and this description were written by Claude Code, directed and reviewed by @codebytere.