benchmark: improve assert benchmarks

This reduces the runtime and makes sure the strict and loose options
can be tested individually.

Besides that a couple of redundant cases were removed.

PR-URL: https://github.com/nodejs/node/pull/22211
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Ruben Bridgewater 2018-08-03 15:30:22 +02:00
parent c29aff3ac7
commit 5442c28b65
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
10 changed files with 68 additions and 189 deletions

View File

@ -3,17 +3,16 @@ const common = require('../common.js');
const assert = require('assert'); const assert = require('assert');
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [1e5], n: [2e4],
len: [1e2, 1e4], len: [1e2, 1e3],
strict: [0, 1],
method: [ method: [
'deepEqual', 'deepEqual',
'deepStrictEqual', 'notDeepEqual'
'notDeepEqual',
'notDeepStrictEqual'
] ]
}); });
function main({ len, n, method }) { function main({ len, n, method, strict }) {
if (!method) if (!method)
method = 'deepEqual'; method = 'deepEqual';
const data = Buffer.allocUnsafe(len + 1); const data = Buffer.allocUnsafe(len + 1);
@ -24,6 +23,9 @@ function main({ len, n, method }) {
data.copy(expected); data.copy(expected);
data.copy(expectedWrong); data.copy(expectedWrong);
if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method]; const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected; const value2 = method.includes('not') ? expectedWrong : expected;

View File

@ -7,21 +7,14 @@ const { deepEqual, deepStrictEqual, notDeepEqual, notDeepStrictEqual } =
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [5e2], n: [5e2],
len: [5e2], len: [5e2],
strict: [0, 1],
method: [ method: [
'deepEqual_primitiveOnly', 'deepEqual_primitiveOnly',
'deepStrictEqual_primitiveOnly',
'deepEqual_objectOnly', 'deepEqual_objectOnly',
'deepStrictEqual_objectOnly',
'deepEqual_mixed', 'deepEqual_mixed',
'deepStrictEqual_mixed',
'deepEqual_looseMatches',
'notDeepEqual_primitiveOnly', 'notDeepEqual_primitiveOnly',
'notDeepStrictEqual_primitiveOnly',
'notDeepEqual_objectOnly', 'notDeepEqual_objectOnly',
'notDeepStrictEqual_objectOnly', 'notDeepEqual_mixed'
'notDeepEqual_mixed',
'notDeepStrictEqual_mixed',
'notDeepEqual_looseMatches',
] ]
}); });
@ -37,7 +30,7 @@ function benchmark(method, n, values, values2) {
bench.end(n); bench.end(n);
} }
function main({ n, len, method }) { function main({ n, len, method, strict }) {
const array = Array(len).fill(1); const array = Array(len).fill(1);
var values, values2; var values, values2;
@ -46,74 +39,33 @@ function main({ n, len, method }) {
// Empty string falls through to next line as default, mostly for tests. // Empty string falls through to next line as default, mostly for tests.
case 'deepEqual_primitiveOnly': case 'deepEqual_primitiveOnly':
values = array.map((_, i) => [`str_${i}`, 123]); values = array.map((_, i) => [`str_${i}`, 123]);
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_primitiveOnly':
values = array.map((_, i) => [`str_${i}`, 123]);
benchmark(deepStrictEqual, n, values);
break; break;
case 'deepEqual_objectOnly': case 'deepEqual_objectOnly':
values = array.map((_, i) => [[`str_${i}`, 1], 123]); values = array.map((_, i) => [[`str_${i}`, 1], 123]);
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_objectOnly':
values = array.map((_, i) => [[`str_${i}`, 1], 123]);
benchmark(deepStrictEqual, n, values);
break; break;
case 'deepEqual_mixed': case 'deepEqual_mixed':
values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]); values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]);
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_mixed':
values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]);
benchmark(deepStrictEqual, n, values);
break;
case 'deepEqual_looseMatches':
values = array.map((_, i) => [i, i]);
values2 = values.slice().map((v) => [String(v[0]), String(v[1])]);
benchmark(deepEqual, n, values, values2);
break; break;
case 'notDeepEqual_primitiveOnly': case 'notDeepEqual_primitiveOnly':
values = array.map((_, i) => [`str_${i}`, 123]); values = array.map((_, i) => [`str_${i}`, 123]);
values2 = values.slice(0); values2 = values.slice(0);
values2[Math.floor(len / 2)] = ['w00t', 123]; values2[Math.floor(len / 2)] = ['w00t', 123];
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_primitiveOnly':
values = array.map((_, i) => [`str_${i}`, 123]);
values2 = values.slice(0);
values2[Math.floor(len / 2)] = ['w00t', 123];
benchmark(notDeepStrictEqual, n, values, values2);
break; break;
case 'notDeepEqual_objectOnly': case 'notDeepEqual_objectOnly':
values = array.map((_, i) => [[`str_${i}`, 1], 123]); values = array.map((_, i) => [[`str_${i}`, 1], 123]);
values2 = values.slice(0); values2 = values.slice(0);
values2[Math.floor(len / 2)] = [['w00t'], 123]; values2[Math.floor(len / 2)] = [['w00t'], 123];
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_objectOnly':
values = array.map((_, i) => [[`str_${i}`, 1], 123]);
values2 = values.slice(0);
values2[Math.floor(len / 2)] = [['w00t'], 123];
benchmark(notDeepStrictEqual, n, values, values2);
break; break;
case 'notDeepEqual_mixed': case 'notDeepEqual_mixed':
values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]); values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]);
values2 = values.slice(0); values2 = values.slice(0);
values2[0] = ['w00t', 123]; values2[0] = ['w00t', 123];
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_mixed':
values = array.map((_, i) => [i % 2 ? [`str_${i}`, 1] : `str_${i}`, 123]);
values2 = values.slice(0);
values2[0] = ['w00t', 123];
benchmark(notDeepStrictEqual, n, values, values2);
break;
case 'notDeepEqual_looseMatches':
values = array.map((_, i) => [i, i]);
values2 = values.slice().map((v) => [String(v[0]), String(v[1])]);
values2[len - 1] = [String(len + 1), String(len + 1)];
benchmark(notDeepEqual, n, values, values2);
break; break;
default: default:
throw new Error(`Unsupported method ${method}`); throw new Error(`Unsupported method ${method}`);

View File

@ -4,13 +4,12 @@ const common = require('../common.js');
const assert = require('assert'); const assert = require('assert');
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [1e6], n: [5e3],
size: [1e2, 1e3, 1e4], size: [1e2, 1e3, 5e4],
strict: [0, 1],
method: [ method: [
'deepEqual', 'deepEqual',
'deepStrictEqual', 'notDeepEqual'
'notDeepEqual',
'notDeepStrictEqual'
] ]
}); });
@ -20,14 +19,16 @@ function createObj(source, add = '') {
nope: { nope: {
bar: `123${add}`, bar: `123${add}`,
a: [1, 2, 3], a: [1, 2, 3],
baz: n baz: n,
c: {},
b: []
} }
})); }));
} }
function main({ size, n, method }) { function main({ size, n, method, strict }) {
// TODO: Fix this "hack". `n` should not be manipulated. // TODO: Fix this "hack". `n` should not be manipulated.
n = n / size; n = Math.min(Math.ceil(n / size), 20);
if (!method) if (!method)
method = 'deepEqual'; method = 'deepEqual';
@ -37,6 +38,9 @@ function main({ size, n, method }) {
const expected = createObj(source); const expected = createObj(source);
const expectedWrong = createObj(source, '4'); const expectedWrong = createObj(source, '4');
if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method]; const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected; const value2 = method.includes('not') ? expectedWrong : expected;

View File

@ -5,29 +5,22 @@ const { deepEqual, deepStrictEqual, notDeepEqual, notDeepStrictEqual } =
require('assert'); require('assert');
const primValues = { const primValues = {
'null': null,
'undefined': undefined,
'string': 'a', 'string': 'a',
'number': 1, 'number': 1,
'boolean': true,
'object': { 0: 'a' }, 'object': { 0: 'a' },
'array': [1, 2, 3], 'array': [1, 2, 3]
'new-array': new Array([1, 2, 3])
}; };
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
primitive: Object.keys(primValues), primitive: Object.keys(primValues),
n: [25], n: [25],
len: [1e5], len: [2e4],
strict: [0, 1],
method: [ method: [
'deepEqual_Array', 'deepEqual_Array',
'deepStrictEqual_Array',
'notDeepEqual_Array', 'notDeepEqual_Array',
'notDeepStrictEqual_Array',
'deepEqual_Set', 'deepEqual_Set',
'deepStrictEqual_Set', 'notDeepEqual_Set'
'notDeepEqual_Set',
'notDeepStrictEqual_Set'
] ]
}); });
@ -39,7 +32,7 @@ function run(fn, n, actual, expected) {
bench.end(n); bench.end(n);
} }
function main({ n, len, primitive, method }) { function main({ n, len, primitive, method, strict }) {
const prim = primValues[primitive]; const prim = primValues[primitive];
const actual = []; const actual = [];
const expected = []; const expected = [];
@ -62,28 +55,17 @@ function main({ n, len, primitive, method }) {
// Empty string falls through to next line as default, mostly for tests. // Empty string falls through to next line as default, mostly for tests.
case '': case '':
case 'deepEqual_Array': case 'deepEqual_Array':
run(deepEqual, n, actual, expected); run(strict ? deepStrictEqual : deepEqual, n, actual, expected);
break;
case 'deepStrictEqual_Array':
run(deepStrictEqual, n, actual, expected);
break; break;
case 'notDeepEqual_Array': case 'notDeepEqual_Array':
run(notDeepEqual, n, actual, expectedWrong); run(strict ? notDeepStrictEqual : notDeepEqual, n, actual, expectedWrong);
break;
case 'notDeepStrictEqual_Array':
run(notDeepStrictEqual, n, actual, expectedWrong);
break; break;
case 'deepEqual_Set': case 'deepEqual_Set':
run(deepEqual, n, actualSet, expectedSet); run(strict ? deepStrictEqual : deepEqual, n, actualSet, expectedSet);
break;
case 'deepStrictEqual_Set':
run(deepStrictEqual, n, actualSet, expectedSet);
break; break;
case 'notDeepEqual_Set': case 'notDeepEqual_Set':
run(notDeepEqual, n, actualSet, expectedWrongSet); run(strict ? notDeepStrictEqual : notDeepEqual,
break; n, actualSet, expectedWrongSet);
case 'notDeepStrictEqual_Set':
run(notDeepStrictEqual, n, actualSet, expectedWrongSet);
break; break;
default: default:
throw new Error(`Unsupported method "${method}"`); throw new Error(`Unsupported method "${method}"`);

View File

@ -3,28 +3,23 @@ const common = require('../common.js');
const assert = require('assert'); const assert = require('assert');
const primValues = { const primValues = {
'null': null,
'undefined': undefined,
'string': 'a', 'string': 'a',
'number': 1, 'number': 1,
'boolean': true,
'object': { 0: 'a' }, 'object': { 0: 'a' },
'array': [1, 2, 3], 'array': [1, 2, 3]
'new-array': new Array([1, 2, 3])
}; };
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
primitive: Object.keys(primValues), primitive: Object.keys(primValues),
n: [1e6], n: [2e4],
strict: [0, 1],
method: [ method: [
'deepEqual', 'deepEqual',
'deepStrictEqual',
'notDeepEqual', 'notDeepEqual',
'notDeepStrictEqual'
] ]
}); });
function main({ n, primitive, method }) { function main({ n, primitive, method, strict }) {
if (!method) if (!method)
method = 'deepEqual'; method = 'deepEqual';
const prim = primValues[primitive]; const prim = primValues[primitive];
@ -32,6 +27,9 @@ function main({ n, primitive, method }) {
const expected = prim; const expected = prim;
const expectedWrong = 'b'; const expectedWrong = 'b';
if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method]; const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected; const value2 = method.includes('not') ? expectedWrong : expected;

View File

@ -7,21 +7,14 @@ const { deepEqual, deepStrictEqual, notDeepEqual, notDeepStrictEqual } =
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [5e2], n: [5e2],
len: [5e2], len: [5e2],
strict: [0, 1],
method: [ method: [
'deepEqual_primitiveOnly', 'deepEqual_primitiveOnly',
'deepStrictEqual_primitiveOnly',
'deepEqual_objectOnly', 'deepEqual_objectOnly',
'deepStrictEqual_objectOnly',
'deepEqual_mixed', 'deepEqual_mixed',
'deepStrictEqual_mixed',
'deepEqual_looseMatches',
'notDeepEqual_primitiveOnly', 'notDeepEqual_primitiveOnly',
'notDeepStrictEqual_primitiveOnly',
'notDeepEqual_objectOnly', 'notDeepEqual_objectOnly',
'notDeepStrictEqual_objectOnly', 'notDeepEqual_mixed'
'notDeepEqual_mixed',
'notDeepStrictEqual_mixed',
'notDeepEqual_looseMatches',
] ]
}); });
@ -37,7 +30,7 @@ function benchmark(method, n, values, values2) {
bench.end(n); bench.end(n);
} }
function main({ n, len, method }) { function main({ n, len, method, strict }) {
const array = Array(len).fill(1); const array = Array(len).fill(1);
var values, values2; var values, values2;
@ -47,60 +40,29 @@ function main({ n, len, method }) {
// Empty string falls through to next line as default, mostly for tests. // Empty string falls through to next line as default, mostly for tests.
case 'deepEqual_primitiveOnly': case 'deepEqual_primitiveOnly':
values = array.map((_, i) => `str_${i}`); values = array.map((_, i) => `str_${i}`);
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_primitiveOnly':
values = array.map((_, i) => `str_${i}`);
benchmark(deepStrictEqual, n, values);
break; break;
case 'deepEqual_objectOnly': case 'deepEqual_objectOnly':
values = array.map((_, i) => [`str_${i}`, null]); values = array.map((_, i) => [`str_${i}`, null]);
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_objectOnly':
values = array.map((_, i) => [`str_${i}`, null]);
benchmark(deepStrictEqual, n, values);
break; break;
case 'deepEqual_mixed': case 'deepEqual_mixed':
values = array.map((_, i) => { values = array.map((_, i) => {
return i % 2 ? [`str_${i}`, null] : `str_${i}`; return i % 2 ? [`str_${i}`, null] : `str_${i}`;
}); });
benchmark(deepEqual, n, values); benchmark(strict ? deepStrictEqual : deepEqual, n, values);
break;
case 'deepStrictEqual_mixed':
values = array.map((_, i) => {
return i % 2 ? [`str_${i}`, null] : `str_${i}`;
});
benchmark(deepStrictEqual, n, values);
break;
case 'deepEqual_looseMatches':
values = array.map((_, i) => i);
values2 = values.slice().map((v) => String(v));
benchmark(deepEqual, n, values, values2);
break; break;
case 'notDeepEqual_primitiveOnly': case 'notDeepEqual_primitiveOnly':
values = array.map((_, i) => `str_${i}`); values = array.map((_, i) => `str_${i}`);
values2 = values.slice(0); values2 = values.slice(0);
values2[Math.floor(len / 2)] = 'w00t'; values2[Math.floor(len / 2)] = 'w00t';
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_primitiveOnly':
values = array.map((_, i) => `str_${i}`);
values2 = values.slice(0);
values2[Math.floor(len / 2)] = 'w00t';
benchmark(notDeepStrictEqual, n, values, values2);
break; break;
case 'notDeepEqual_objectOnly': case 'notDeepEqual_objectOnly':
values = array.map((_, i) => [`str_${i}`, null]); values = array.map((_, i) => [`str_${i}`, null]);
values2 = values.slice(0); values2 = values.slice(0);
values2[Math.floor(len / 2)] = ['w00t']; values2[Math.floor(len / 2)] = ['w00t'];
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_objectOnly':
values = array.map((_, i) => [`str_${i}`, null]);
values2 = values.slice(0);
values2[Math.floor(len / 2)] = ['w00t'];
benchmark(notDeepStrictEqual, n, values, values2);
break; break;
case 'notDeepEqual_mixed': case 'notDeepEqual_mixed':
values = array.map((_, i) => { values = array.map((_, i) => {
@ -108,21 +70,7 @@ function main({ n, len, method }) {
}); });
values2 = values.slice(); values2 = values.slice();
values2[0] = 'w00t'; values2[0] = 'w00t';
benchmark(notDeepEqual, n, values, values2); benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
break;
case 'notDeepStrictEqual_mixed':
values = array.map((_, i) => {
return i % 2 ? [`str_${i}`, null] : `str_${i}`;
});
values2 = values.slice();
values2[0] = 'w00t';
benchmark(notDeepStrictEqual, n, values, values2);
break;
case 'notDeepEqual_looseMatches':
values = array.map((_, i) => i);
values2 = values.slice().map((v) => String(v));
values2[len - 1] = String(len + 1);
benchmark(notDeepEqual, n, values, values2);
break; break;
default: default:
throw new Error(`Unsupported method "${method}"`); throw new Error(`Unsupported method "${method}"`);

View File

@ -6,39 +6,39 @@ const bench = common.createBenchmark(main, {
type: [ type: [
'Int8Array', 'Int8Array',
'Uint8Array', 'Uint8Array',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array', 'Float32Array',
'Float64Array', 'Float64Array',
'Uint8ClampedArray', 'Uint8ClampedArray',
], ],
n: [1], n: [5e2],
strict: [0, 1],
method: [ method: [
'deepEqual', 'deepEqual',
'deepStrictEqual',
'notDeepEqual', 'notDeepEqual',
'notDeepStrictEqual'
], ],
len: [1e6] len: [1e2, 5e3]
}); });
function main({ type, n, len, method }) { function main({ type, n, len, method, strict }) {
if (!method) if (!method)
method = 'deepEqual'; method = 'deepEqual';
const clazz = global[type]; const clazz = global[type];
const actual = new clazz(len); const actual = new clazz(len);
const expected = new clazz(len); const expected = new clazz(len);
const expectedWrong = Buffer.alloc(len); const expectedWrong = new clazz(len);
const wrongIndex = Math.floor(len / 2); const wrongIndex = Math.floor(len / 2);
expectedWrong[wrongIndex] = 123; expectedWrong[wrongIndex] = 123;
if (strict) {
method = method.replace('eep', 'eepStrict');
}
const fn = assert[method]; const fn = assert[method];
const value2 = method.includes('not') ? expectedWrong : expected; const value2 = method.includes('not') ? expectedWrong : expected;
bench.start(); bench.start();
for (var i = 0; i < n; ++i) { for (var i = 0; i < n; ++i) {
actual[0] = i;
value2[0] = i;
fn(actual, value2); fn(actual, value2);
} }
bench.end(n); bench.end(n);

View File

@ -4,7 +4,7 @@ const common = require('../common.js');
const assert = require('assert'); const assert = require('assert');
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [1e9] n: [1e5]
}); });
function main({ n }) { function main({ n }) {

View File

@ -4,10 +4,9 @@ const common = require('../common.js');
const { throws, doesNotThrow } = require('assert'); const { throws, doesNotThrow } = require('assert');
const bench = common.createBenchmark(main, { const bench = common.createBenchmark(main, {
n: [1e6], n: [1e4],
method: [ method: [
'doesNotThrow', 'doesNotThrow',
'throws',
'throws_TypeError', 'throws_TypeError',
'throws_RegExp' 'throws_RegExp'
] ]
@ -30,13 +29,6 @@ function main({ n, method }) {
} }
bench.end(n); bench.end(n);
break; break;
case 'throws':
bench.start();
for (i = 0; i < n; ++i) {
throws(throwError);
}
bench.end(n);
break;
case 'throws_TypeError': case 'throws_TypeError':
bench.start(); bench.start();
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {

View File

@ -10,6 +10,7 @@ const runBenchmark = require('../common/benchmark');
runBenchmark( runBenchmark(
'assert', 'assert',
[ [
'strict=1',
'len=1', 'len=1',
'method=', 'method=',
'n=1', 'n=1',