lib: avoid quadratic shift() in startup snapshot callback

PR-URL: https://github.com/nodejs/node/pull/62914
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Ilyas Shabi <ilyasshabi94@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Daijiro Wachi committed 2026-04-27 23:17:57 +09:00
1 parent 19f9098968
commit b6b6e960cf
2 files changed
+67 -6

No files matched your search

@@ -0,0 +1,58 @@
'use strict';
// Benchmarks startup time when deserialize callbacks are registered in a
// startup snapshot, measuring real binary execution with --snapshot-blob.
const common = require('../common.js');
const { spawnSync } = require('child_process');
const { mkdtempSync, writeFileSync, rmSync } = require('fs');
const { tmpdir } = require('os');
const path = require('path');
const bench = common.createBenchmark(main, {
count: [10, 100, 1000, 10000],
n: [30],
});
function buildSnapshot(snapshotBlob, fixtureScript, count) {
writeFileSync(fixtureScript, `
'use strict';
const v8 = require('node:v8');
for (let i = 0; i < ${count}; i++) {
v8.startupSnapshot.addDeserializeCallback(() => {});
}
v8.startupSnapshot.setDeserializeMainFunction(() => {});
`);
const result = spawnSync(process.execPath, [
'--snapshot-blob', snapshotBlob,
'--build-snapshot', fixtureScript,
]);
if (result.status !== 0) {
throw new Error(`Failed to build snapshot:\n${result.stderr}`);
}
}
function main({ n, count }) {
const dir = mkdtempSync(path.join(tmpdir(), 'node-bench-snapshot-'));
const snapshotBlob = path.join(dir, 'snapshot.blob');
const fixtureScript = path.join(dir, 'build.js');
try {
buildSnapshot(snapshotBlob, fixtureScript, count);
const warmup = 3;
let finished = -warmup;
while (finished < n) {
const child = spawnSync(process.execPath, ['--snapshot-blob', snapshotBlob]);
if (child.status !== 0) {
throw new Error(`Snapshot run failed:\n${child.stderr}`);
}
finished++;
if (finished === 0) bench.start();
if (finished === n) bench.end(n);
}
} finally {
rmSync(dir, { recursive: true, force: true });
}
}
+9 -6
View File
@@ -37,10 +37,11 @@ function throwIfBuildingSnapshot(reason) {
const deserializeCallbacks = [];
let deserializeCallbackIsSet = false;
function runDeserializeCallbacks() {
while (deserializeCallbacks.length > 0) {
const { 0: callback, 1: data } = deserializeCallbacks.shift();
for (let i = 0; i < deserializeCallbacks.length; i++) {
const { 0: callback, 1: data } = deserializeCallbacks[i];
callback(data);
}
deserializeCallbacks.length = 0;
}
function addDeserializeCallback(callback, data) {
@@ -60,14 +61,16 @@ function addDeserializeCallback(callback, data) {
const serializeCallbacks = [];
const afterUserSerializeCallbacks = []; // Callbacks to run after user callbacks
function runSerializeCallbacks() {
while (serializeCallbacks.length > 0) {
const { 0: callback, 1: data } = serializeCallbacks.shift();
for (let i = 0; i < serializeCallbacks.length; i++) {
const { 0: callback, 1: data } = serializeCallbacks[i];
callback(data);
}
while (afterUserSerializeCallbacks.length > 0) {
const { 0: callback, 1: data } = afterUserSerializeCallbacks.shift();
serializeCallbacks.length = 0;
for (let i = 0; i < afterUserSerializeCallbacks.length; i++) {
const { 0: callback, 1: data } = afterUserSerializeCallbacks[i];
callback(data);
}
afterUserSerializeCallbacks.length = 0;
}
function addSerializeCallback(callback, data) {