Skip to content

Commit

Permalink
benchmark: rework assert benchmarks for correctness
Browse files Browse the repository at this point in the history
This reworks most assert benchmarks to provide more reliable test
cases that also test more cases than before while keeping the
runtime low.

Signed-off-by: Ruben Bridgewater <ruben@bridgewater.de>
PR-URL: #46593
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
BridgeAR authored and targos committed Mar 13, 2023
1 parent c786ed3 commit 86b3621
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 131 deletions.
42 changes: 31 additions & 11 deletions benchmark/assert/deepequal-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,47 @@ const bench = common.createBenchmark(main, {
n: [2e4],
len: [1e2, 1e3],
strict: [0, 1],
method: ['deepEqual', 'notDeepEqual'],
arrayBuffer: [0, 1],
method: ['deepEqual', 'notDeepEqual', 'unequal_length'],
}, {
combinationFilter: (p) => {
return p.strict === 1 || p.method === 'deepEqual';
},
});

function main({ len, n, method, strict }) {
const data = Buffer.allocUnsafe(len + 1);
const actual = Buffer.alloc(len);
const expected = Buffer.alloc(len);
const expectedWrong = Buffer.alloc(len + 1);
data.copy(actual);
data.copy(expected);
data.copy(expectedWrong);
function main({ len, n, method, strict, arrayBuffer }) {
let actual = Buffer.alloc(len);
let expected = Buffer.alloc(len + Number(method === 'unequal_length'));


if (method === 'unequal_length') {
method = 'notDeepEqual';
}

for (let i = 0; i < len; i++) {
actual.writeInt8(i % 128, i);
expected.writeInt8(i % 128, i);
}

if (method.includes('not')) {
const position = Math.floor(len / 2);
expected[position] = expected[position] + 1;
}

if (strict) {
method = method.replace('eep', 'eepStrict');
}

const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected;

if (arrayBuffer) {
actual = actual.buffer;
expected = expected.buffer;
}

bench.start();
for (let i = 0; i < n; ++i) {
fn(actual, value2);
fn(actual, expected);
}
bench.end(n);
}
33 changes: 17 additions & 16 deletions benchmark/assert/deepequal-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ const common = require('../common.js');
const assert = require('assert');

const bench = common.createBenchmark(main, {
n: [5e3],
size: [1e2, 1e3, 5e4],
strict: [0, 1],
n: [25, 2e2, 2e3],
size: [1e2, 1e3, 1e4],
strict: [1],
method: ['deepEqual', 'notDeepEqual'],
}, {
combinationFilter: (p) => {
return p.size === 1e4 && p.n === 25 ||
p.size === 1e3 && p.n === 2e2 ||
p.size === 1e2 && p.n === 2e3;
},
});

function createObj(source, add = '') {
return source.map((n) => ({
function createObj(size, add = '') {
return Array.from({ length: size }, (n) => ({
foo: 'yarp',
nope: {
bar: `123${add}`,
Expand All @@ -24,22 +30,17 @@ function createObj(source, add = '') {
}

function main({ size, n, method, strict }) {
const len = Math.min(Math.ceil(n / size), 20);

const source = Array.apply(null, Array(size));
const actual = createObj(source);
const expected = createObj(source);
const expectedWrong = createObj(source, '4');

if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected;

const actual = createObj(size);
const expected = method.includes('not') ? createObj(size, '4') : createObj(size);

bench.start();
for (let i = 0; i < len; ++i) {
fn(actual, value2);
for (let i = 0; i < n; ++i) {
fn(actual, expected);
}
bench.end(len);
bench.end(n);
}
60 changes: 51 additions & 9 deletions benchmark/assert/deepequal-prims-and-objs-big-loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,77 @@
const common = require('../common.js');
const assert = require('assert');

const circular = {};
circular.circular = circular;
const circular2 = {};
circular2.circular = circular2;
const notCircular = {};
notCircular.circular = {};

const primValues = {
'string': 'a',
'number': 1,
'object': { 0: 'a' },
'string': 'abcdef',
'number': 1_000,
'boolean': true,
'object': { property: 'abcdef' },
'object_other_property': { property: 'abcdef' },
'array': [1, 2, 3],
'set_object': new Set([[1]]),
'set_simple': new Set([1, 2, 3]),
'circular': circular,
'empty_object': {},
'regexp': /abc/i,
'date': new Date(),
};

const primValues2 = {
'object': { property: 'abcdef' },
'array': [1, 2, 3],
'set_object': new Set([[1]]),
'set_simple': new Set([1, 3, 2]),
'circular': circular2,
'empty_object': {},
'regexp': /abc/i,
'date': new Date(primValues.date),
};

const primValuesUnequal = {
'string': 'abcdez',
'number': 1_001,
'boolean': false,
'object': { property2: 'abcdef' },
'array': [1, 3, 2],
'set_object': new Set([[2]]),
'set_simple': new Set([1, 4, 2]),
'circular': notCircular,
'empty_object': [],
'regexp': /abc/g,
'date': new Date(primValues.date.getTime() + 1),
};

const bench = common.createBenchmark(main, {
primitive: Object.keys(primValues),
n: [2e4],
n: [1e5],
strict: [0, 1],
method: ['deepEqual', 'notDeepEqual'],
}, {
combinationFilter: (p) => {
return p.strict === 1 || p.method === 'deepEqual';
},
});

function main({ n, primitive, method, strict }) {
const prim = primValues[primitive];
const actual = prim;
const expected = prim;
const expectedWrong = 'b';
const actual = primValues2[primitive] ?? prim;
const expected = method.includes('not') ? primValuesUnequal[primitive] : prim;

if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected;

bench.start();
for (let i = 0; i < n; ++i) {
fn([actual], [value2]);
fn(actual, expected);
}
bench.end(n);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ const common = require('../common.js');
const { deepEqual, deepStrictEqual, notDeepEqual, notDeepStrictEqual } =
require('assert');

const primValues = {
'string': 'a',
'number': 1,
'object': { 0: 'a' },
'array': [1, 2, 3],
};

const bench = common.createBenchmark(main, {
primitive: Object.keys(primValues),
n: [25],
len: [2e4],
strict: [0, 1],
n: [5e2],
len: [1e4],
strict: [1],
method: [
'deepEqual_Array',
'notDeepEqual_Array',
Expand All @@ -32,38 +24,32 @@ function run(fn, n, actual, expected) {
bench.end(n);
}

function main({ n, len, primitive, method, strict }) {
const prim = primValues[primitive];
function main({ n, len, method, strict }) {
const actual = [];
const expected = [];
const expectedWrong = [];

for (let x = 0; x < len; x++) {
actual.push(prim);
expected.push(prim);
expectedWrong.push(prim);
for (let i = 0; i < len; i++) {
actual.push(i);
expected.push(i);
}
if (method.includes('not')) {
expected[len - 1] += 1;
}
expectedWrong.pop();
expectedWrong.push('b');

// Note: primitives are only added once to a set
const actualSet = new Set(actual);
const expectedSet = new Set(expected);
const expectedWrongSet = new Set(expectedWrong);

switch (method) {
case 'deepEqual_Array':
run(strict ? deepStrictEqual : deepEqual, n, actual, expected);
break;
case 'notDeepEqual_Array':
run(strict ? notDeepStrictEqual : notDeepEqual, n, actual, expectedWrong);
run(strict ? notDeepStrictEqual : notDeepEqual, n, actual, expected);
break;
case 'deepEqual_Set':
run(strict ? deepStrictEqual : deepEqual, n, actualSet, expectedSet);
run(strict ? deepStrictEqual : deepEqual,
n, new Set(actual), new Set(expected));
break;
case 'notDeepEqual_Set':
run(strict ? notDeepStrictEqual : notDeepEqual,
n, actualSet, expectedWrongSet);
n, new Set(actual), new Set(expected));
break;
default:
throw new Error(`Unsupported method "${method}"`);
Expand Down
18 changes: 10 additions & 8 deletions benchmark/assert/deepequal-typedarrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ const bench = common.createBenchmark(main, {
'Int8Array',
'Uint8Array',
'Float32Array',
'Float64Array',
'Uint8ClampedArray',
'Uint32Array',
],
n: [5e2],
strict: [0, 1],
Expand All @@ -23,21 +22,24 @@ function main({ type, n, len, method, strict }) {
const clazz = global[type];
const actual = new clazz(len);
const expected = new clazz(len);
const expectedWrong = new clazz(len);
const wrongIndex = Math.floor(len / 2);
expectedWrong[wrongIndex] = 123;

if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected;

if (method.includes('not')) {
expected[Math.floor(len / 2)] = 123;
}

bench.start();
for (let i = 0; i < n; ++i) {
actual[0] = i;
value2[0] = i;
fn(actual, value2);
expected[0] = i;
const pos = Math.ceil(len / 2) + 1;
actual[pos] = i;
expected[pos] = i;
fn(actual, expected);
}
bench.end(n);
}
17 changes: 0 additions & 17 deletions benchmark/assert/ok.js

This file was deleted.

42 changes: 0 additions & 42 deletions benchmark/assert/throws.js

This file was deleted.

0 comments on commit 86b3621

Please sign in to comment.