Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions benchmark/test_runner/mock-timers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
'use strict';

const common = require('../common');
const assert = require('node:assert');
const { test } = require('node:test');
const nodeTimersPromises = require('node:timers/promises');

const bench = common.createBenchmark(main, {
n: [1, 10, 100, 1000],
mode: [
'enable-empty-apis',
'enable-setTimeout',
'enable-setInterval',
'enable-setImmediate',
'enable-Date',
'enable-scheduler.wait',
'enable-AbortSignal.timeout',
'enable-all',
'enable-default',
'setTimeout',
'setInterval',
'setImmediate',
'scheduler.wait',
'AbortSignal.timeout',
'Date',
'setTime',
'runAll',
],
}, {
// We don't want to test the reporter here.
flags: ['--test-reporter=./benchmark/fixtures/empty-test-reporter.js'],
});

function benchmarkEnable(n, mode) {
const enableMode = mode.replace('enable-', '');
let enableOptions = { apis: [enableMode] };

if (enableMode === 'all') {
enableOptions.apis = ['setTimeout', 'setInterval', 'setImmediate', 'Date', 'scheduler.wait', 'AbortSignal.timeout'];
}

if (enableMode === 'empty-apis') {
enableOptions.apis = [];
}

if (enableMode === 'default') {
enableOptions = undefined;
}

test((t) => {
bench.start();

for (let i = 0; i < n; i++) {
t.mock.timers.enable(enableOptions);
t.mock.timers.reset();
}

bench.end(n);
});
}

function benchmarkSetTimeout(n) {
test((t) => {
let noDead;

t.mock.timers.enable({ apis: ['setTimeout'] });
bench.start();

for (let i = 0; i < n; i++) {
setTimeout(() => {
noDead = i;
}, i + 1);
}

t.mock.timers.tick(n + 1);
bench.end(n);

assert.strictEqual(noDead, n - 1);
});
}

function benchmarkSetInterval(n) {
test((t) => {
let noDead = 0;

t.mock.timers.enable({ apis: ['setInterval'] });

setInterval(() => {
noDead++;
}, 1);

bench.start();

t.mock.timers.tick(n);

bench.end(n);

assert.strictEqual(noDead, n);
});
}

function benchmarkSetImmediate(n) {
test((t) => {
let noDead;

t.mock.timers.enable({ apis: ['setImmediate'] });

bench.start();

for (let i = 0; i < n; i++) {
setImmediate(() => {
noDead = i;
});
}

t.mock.timers.tick(0);
bench.end(n);

assert.strictEqual(noDead, n - 1);
});
}

function benchmarkSchedulerWait(n) {
test(async (t) => {
const promises = [];
let noDead;

t.mock.timers.enable({ apis: ['scheduler.wait'] });

bench.start();

for (let i = 0; i < n; i++) {
promises.push(nodeTimersPromises.scheduler.wait(i + 1).then(() => {
noDead = i;
}));
}

t.mock.timers.tick(n + 1);
await Promise.all(promises);
bench.end(n);

assert.strictEqual(noDead, n - 1);
});
}

function benchmarkAbortSignalTimeout(n) {
test((t) => {
let noDead;

t.mock.timers.enable({ apis: ['AbortSignal.timeout'] });

bench.start();

for (let i = 0; i < n; i++) {
noDead = AbortSignal.timeout(i + 1);
}

t.mock.timers.tick(n + 1);
bench.end(n);

assert.strictEqual(noDead.aborted, true);
});
}

function benchmarkDate(n) {
test((t) => {
let noDead;

t.mock.timers.enable({ apis: ['Date'] });

bench.start();

for (let i = 0; i < n; i++) {
noDead = Date.now();
}

bench.end(n);

assert.strictEqual(noDead, 0);
});
}

function benchmarkSetTime(n) {
test((t) => {
let noDead;

t.mock.timers.enable({ apis: ['Date'] });

bench.start();

for (let i = 0; i < n; i++) {
t.mock.timers.setTime(i);
noDead = Date.now();
}

bench.end(n);

assert.strictEqual(noDead, n - 1);
});
}

function benchmarkRunAll(n) {
test((t) => {
let noDead = 0;

t.mock.timers.enable({ apis: ['setTimeout'] });

for (let i = 0; i < n; i++) {
setTimeout(() => {
noDead++;
}, i + 1);
}

bench.start();

t.mock.timers.runAll();

bench.end(n);

assert.strictEqual(noDead, n);
});
}

function main({ n, mode }) {
switch (mode) {
case 'enable-empty-apis':
case 'enable-setTimeout':
case 'enable-setInterval':
case 'enable-setImmediate':
case 'enable-Date':
case 'enable-scheduler.wait':
case 'enable-AbortSignal.timeout':
case 'enable-all':
case 'enable-default':
benchmarkEnable(n, mode);
break;
case 'setTimeout':
benchmarkSetTimeout(n);
break;
case 'setInterval':
benchmarkSetInterval(n);
break;
case 'setImmediate':
benchmarkSetImmediate(n);
break;
case 'scheduler.wait':
benchmarkSchedulerWait(n);
break;
case 'AbortSignal.timeout':
benchmarkAbortSignalTimeout(n);
break;
case 'Date':
benchmarkDate(n);
break;
case 'setTime':
benchmarkSetTime(n);
break;
case 'runAll':
benchmarkRunAll(n);
break;
}
}
44 changes: 44 additions & 0 deletions benchmark/test_runner/test-only.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

const common = require('../common');
const { finished } = require('node:stream/promises');
const reporter = require('../fixtures/empty-test-reporter');
const { test } = require('node:test');

const bench = common.createBenchmark(main, {
n: [1, 10, 100, 1000],
selected: [1],
}, {
// We don't want to test the reporter here.
flags: [
'--test-reporter=./benchmark/fixtures/empty-test-reporter.js',
'--test-only',
],
});

async function run({ n, selected }) {
// eslint-disable-next-line no-unused-vars
let avoidV8Optimization;

for (let i = 0; i < selected; i++) {
test(`selected-${i}`, { only: true }, () => {
avoidV8Optimization = i;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary; it's a clojure. Adding an assert.ok is probably more useful.

@luanmuniz luanmuniz Jun 24, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @RafaelGSS, thanks for taking a look.

Just to make sure I understand the suggestion: are you suggesting replacing the avoidV8Optimization assignment with an assertion inside the benchmarked section?

I added the avoidV8Optimization bit to avoid making the benchmarked callback completely empty, as detailed in the previous PR: #63754 (comment)

My concern with adding assert.ok() inside the callback is that the assertion itself would become part of what is being measured. Adding extra work inside the benchmark was also something @avivkeller raised in the previous PR: #63754 (comment)

I’m happy to adjust it either way. Please let me know how to proceed.

Thank you for the guidance.

Obs: I see the comments about calbrate-n on the first PR and i will push that change very soon here too

});
}

for (let i = 0; i < n; i++) {
test(`not-selected-${i}`, () => {
throw new Error(`This test ${i} should not run.`);
});
}

return finished(reporter);
}

function main(params) {
bench.start();

run(params).then(() => {
bench.end(params.n);
});
}
Loading