From 5e167bd6589e945ab1e3f40caafd44891e73600b Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 8 Dec 2022 15:50:18 +0100 Subject: [PATCH] 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 Reviewed-By: Yagiz Nizipli Reviewed-By: Anna Henningsen --- benchmark/common.js | 8 +-- benchmark/fixtures/require-cachable.js | 10 --- benchmark/misc/startup.js | 89 +++++++++++--------------- 3 files changed, 43 insertions(+), 64 deletions(-) delete mode 100644 benchmark/fixtures/require-cachable.js diff --git a/benchmark/common.js b/benchmark/common.js index 6ed230ffde4231..918eaa5e0adbb4 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -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(); } diff --git a/benchmark/fixtures/require-cachable.js b/benchmark/fixtures/require-cachable.js deleted file mode 100644 index 105652a51855eb..00000000000000 --- a/benchmark/fixtures/require-cachable.js +++ /dev/null @@ -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}`); -} diff --git a/benchmark/misc/startup.js b/benchmark/misc/startup.js index dea5a31753f8fe..c2cf7f2de658be 100644 --- a/benchmark/misc/startup.js +++ b/benchmark/misc/startup.js @@ -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); -} + 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.finished++; + if (state.finished === 0) { + // Finished warmup. + bench.start(); + } -function spawnWorker(script) { - return new Worker(script, { stderr: true, stdout: true }); + if (state.finished === state.count) { + bench.end(state.count); + } + } } -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) => { +function spawnWorker(script, bench, state) { + const child = new Worker(script); + child.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}`); + throw new Error(`Worker stopped with exit code ${code}`); } - state.throughput++; - - if (state.go) { - start(state, script, bench, getNode); + state.finished++; + if (state.finished === 0) { + // Finished warmup. + bench.start(); + } + if (state.finished < state.count) { + spawnProcess(script, bench, state); } else { - bench.end(state.throughput); + bench.end(state.count); } }); } -function main({ dur, script, mode }) { - const state = { - go: true, - throughput: 0 - }; - - setTimeout(() => { - state.go = false; - }, dur * 1000); - +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; - bench.start(); - start(state, script, bench, spawnWorker); + spawnWorker(script, bench, state); } else { - bench.start(); - start(state, script, bench, spawnProcess); + spawnProcess(script, bench, state); } }