benchmark: make benchmarks runnable in older versions of Node.js

Also remove the require-cachable.js benchmarks because now all builtin
modules are cacheable, it would be comparing oranges to apples when
we try to compare the performance of loading all cacheable modules
in different Node.js binaries since the set of modules are just
different. Comparison of startup performance that involves loading
of the long-standing, stable builtins is already covered by the
require-builtins benchmark.

PR-URL: https://github.com/nodejs/node/pull/45746
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Joyee Cheung 2022-12-08 15:50:18 +01:00 committed by GitHub
parent 3f98be90ea
commit 2b9d3b2755
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 75 deletions

View File

@ -38,7 +38,7 @@ class Benchmark {
this.config = this.queue[0];
process.nextTick(() => {
if (Object.hasOwn(process.env, 'NODE_RUN_BENCHMARK_FN')) {
if (process.env.NODE_RUN_BENCHMARK_FN !== undefined) {
fn(this.config);
} else {
// _run will use fork() to create a new process for each configuration
@ -91,7 +91,7 @@ class Benchmark {
process.exit(1);
}
const [, key, value] = match;
if (Object.hasOwn(configs, key)) {
if (configs[key] !== undefined) {
if (!cliOptions[key])
cliOptions[key] = [];
cliOptions[key].push(
@ -290,10 +290,10 @@ function sendResult(data) {
if (process.send) {
// If forked, report by process send
process.send(data, () => {
if (Object.hasOwn(process.env, 'NODE_RUN_BENCHMARK_FN')) {
if (process.env.NODE_RUN_BENCHMARK_FN !== undefined) {
// If, for any reason, the process is unable to self close within
// a second after completing, forcefully close it.
setTimeout(() => {
require('timers').setTimeout(() => {
process.exit(0);
}, 5000).unref();
}

View File

@ -1,10 +0,0 @@
'use strict';
const { internalBinding } = require('internal/test/binding');
const {
builtinCategories: { canBeRequired }
} = internalBinding('builtins');
for (const key of canBeRequired) {
require(`node:${key}`);
}

View File

@ -1,80 +1,69 @@
'use strict';
const common = require('../common.js');
const { spawn } = require('child_process');
const { spawnSync } = require('child_process');
const path = require('path');
let Worker; // Lazy loaded in main
const bench = common.createBenchmark(main, {
dur: [1],
script: [
'benchmark/fixtures/require-builtins',
'benchmark/fixtures/require-cachable',
'test/fixtures/semicolon',
],
mode: ['process', 'worker']
}, {
flags: ['--expose-internals']
mode: ['process', 'worker'],
count: [30],
});
function spawnProcess(script) {
function spawnProcess(script, bench, state) {
const cmd = process.execPath || process.argv[0];
const argv = ['--expose-internals', script];
return spawn(cmd, argv);
}
function spawnWorker(script) {
return new Worker(script, { stderr: true, stdout: true });
}
function start(state, script, bench, getNode) {
const node = getNode(script);
let stdout = '';
let stderr = '';
node.stdout.on('data', (data) => {
stdout += data;
});
node.stderr.on('data', (data) => {
stderr += data;
});
node.on('exit', (code) => {
if (code !== 0) {
console.error('------ stdout ------');
console.error(stdout);
console.error('------ stderr ------');
console.error(stderr);
throw new Error(`Error during node startup, exit code ${code}`);
while (state.finished < state.count) {
const child = spawnSync(cmd, [script]);
if (child.status !== 0) {
console.log('---- STDOUT ----');
console.log(child.stdout.toString());
console.log('---- STDERR ----');
console.log(child.stderr.toString());
throw new Error(`Child process stopped with exit code ${child.status}`);
}
state.throughput++;
if (state.go) {
start(state, script, bench, getNode);
} else {
bench.end(state.throughput);
state.finished++;
if (state.finished === 0) {
// Finished warmup.
bench.start();
}
});
}
function main({ dur, script, mode }) {
const state = {
go: true,
throughput: 0
};
setTimeout(() => {
state.go = false;
}, dur * 1000);
script = path.resolve(__dirname, '../../', `${script}.js`);
if (mode === 'worker') {
Worker = require('worker_threads').Worker;
bench.start();
start(state, script, bench, spawnWorker);
} else {
bench.start();
start(state, script, bench, spawnProcess);
if (state.finished === state.count) {
bench.end(state.count);
}
}
}
function spawnWorker(script, bench, state) {
const child = new Worker(script);
child.on('exit', (code) => {
if (code !== 0) {
throw new Error(`Worker stopped with exit code ${code}`);
}
state.finished++;
if (state.finished === 0) {
// Finished warmup.
bench.start();
}
if (state.finished < state.count) {
spawnProcess(script, bench, state);
} else {
bench.end(state.count);
}
});
}
function main({ count, script, mode }) {
script = path.resolve(__dirname, '../../', `${script}.js`);
const warmup = 3;
const state = { count, finished: -warmup };
if (mode === 'worker') {
Worker = require('worker_threads').Worker;
spawnWorker(script, bench, state);
} else {
spawnProcess(script, bench, state);
}
}