mirror of https://github.com/nodejs/node.git
lib: improve performance of validateStringArray and validateBooleanArray
PR-URL: https://github.com/nodejs/node/pull/49756 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
parent
d370ed0cd8
commit
a58ffad656
|
@ -0,0 +1,61 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e7],
|
||||
value: [
|
||||
"'777'",
|
||||
'0o777',
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
function getParseFactory() {
|
||||
const {
|
||||
parseFileMode,
|
||||
} = require('internal/validators');
|
||||
|
||||
return (n) => parseFileMode(n, 'n');
|
||||
}
|
||||
|
||||
function main({ n, value }) {
|
||||
const parse = getParseFactory();
|
||||
|
||||
value = value === "'777'" ? '777' : 0o777;
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
let errCase = false;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
try {
|
||||
array.push(parse(value));
|
||||
} catch (e) {
|
||||
errCase = true;
|
||||
array.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
bench.start();
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
try {
|
||||
array[index] = parse(value);
|
||||
} catch (e) {
|
||||
array[index] = e;
|
||||
}
|
||||
}
|
||||
|
||||
bench.end(n);
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], errCase ? 'object' : 'number');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e7],
|
||||
value: [
|
||||
'[]',
|
||||
'[1,2,3]',
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
function getValidateFactory() {
|
||||
const {
|
||||
validateArray,
|
||||
} = require('internal/validators');
|
||||
|
||||
return (n) => validateArray(n, 'n');
|
||||
}
|
||||
|
||||
function main({ n, value }) {
|
||||
const validate = getValidateFactory();
|
||||
|
||||
switch (value) {
|
||||
case '[]':
|
||||
value = [];
|
||||
break;
|
||||
case '[1,2,3]':
|
||||
value = [1, 2, 3];
|
||||
break;
|
||||
}
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
let errCase = false;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
try {
|
||||
array.push(validate(value));
|
||||
} catch (e) {
|
||||
errCase = true;
|
||||
array.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
bench.start();
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
try {
|
||||
array[index] = validate(value);
|
||||
} catch (e) {
|
||||
array[index] = e;
|
||||
}
|
||||
}
|
||||
|
||||
bench.end(n);
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], errCase ? 'object' : 'undefined');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e8],
|
||||
code: [
|
||||
'validateBoolean',
|
||||
],
|
||||
value: [
|
||||
'true',
|
||||
'false',
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
function getValidateFactory(code) {
|
||||
const {
|
||||
validateBoolean,
|
||||
} = require('internal/validators');
|
||||
|
||||
switch (code) {
|
||||
case 'validateBoolean':
|
||||
return (n) => validateBoolean(n, 'n');
|
||||
}
|
||||
}
|
||||
|
||||
function main({ n, code, value }) {
|
||||
const validate = getValidateFactory(code);
|
||||
const v = value === 'true';
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
for (let i = 0; i < length; ++i) {
|
||||
array.push(validate(v));
|
||||
}
|
||||
|
||||
bench.start();
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
array[index] = validate(v);
|
||||
}
|
||||
|
||||
bench.end(n);
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], 'undefined');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e8],
|
||||
encoding: [
|
||||
'ascii',
|
||||
'utf8',
|
||||
'utf-8',
|
||||
'utf16le',
|
||||
'ucs2',
|
||||
'ucs-2',
|
||||
'base64',
|
||||
'latin1',
|
||||
'binary',
|
||||
'hex',
|
||||
],
|
||||
value: [
|
||||
'test',
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
function getValidateFactory(encoding) {
|
||||
const {
|
||||
validateEncoding,
|
||||
} = require('internal/validators');
|
||||
|
||||
return (n) => validateEncoding(n, encoding);
|
||||
}
|
||||
|
||||
function main({ n, encoding, value }) {
|
||||
const validate = getValidateFactory(encoding);
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
for (let i = 0; i < length; ++i) {
|
||||
array.push(validate(value));
|
||||
}
|
||||
|
||||
bench.start();
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
array[index] = validate(value);
|
||||
}
|
||||
|
||||
bench.end(n);
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], 'undefined');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e7],
|
||||
code: [
|
||||
'validateOneOf',
|
||||
],
|
||||
value: [
|
||||
'fifo',
|
||||
'lifo',
|
||||
'lilo',
|
||||
],
|
||||
validLength: [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
const validValues = [
|
||||
'fifo',
|
||||
'lifo',
|
||||
'lilo',
|
||||
'filo',
|
||||
];
|
||||
|
||||
function getValidateFactory(code, validLength) {
|
||||
const {
|
||||
validateOneOf,
|
||||
} = require('internal/validators');
|
||||
|
||||
switch (code) {
|
||||
case 'validateOneOf':
|
||||
return (n) => validateOneOf(n, 'n', validValues.slice(0, validLength));
|
||||
}
|
||||
}
|
||||
|
||||
function main({ n, code, validLength }) {
|
||||
const validate = getValidateFactory(code, validLength);
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
|
||||
const value = validValues[validLength - 1];
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
array.push(validate(value));
|
||||
}
|
||||
|
||||
bench.start();
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
array[index] = validate(value);
|
||||
}
|
||||
bench.end(n);
|
||||
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], 'undefined');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [1e8],
|
||||
type: [
|
||||
'validateStringArray',
|
||||
'validateBooleanArray',
|
||||
],
|
||||
arrayLength: [
|
||||
0,
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
],
|
||||
}, {
|
||||
flags: ['--expose-internals'],
|
||||
});
|
||||
|
||||
function getValidateFactory(type, arrayLength) {
|
||||
const {
|
||||
validateBooleanArray,
|
||||
validateStringArray,
|
||||
} = require('internal/validators');
|
||||
|
||||
switch (type) {
|
||||
case 'validateBooleanArray':
|
||||
return [
|
||||
(n) => validateBooleanArray(n, 'n'),
|
||||
Array.from({ length: arrayLength }, (v, i) => ((i & 1) === 0)),
|
||||
];
|
||||
case 'validateStringArray':
|
||||
return [
|
||||
(n) => validateStringArray(n, 'n'),
|
||||
Array.from({ length: arrayLength }, (v, i) => `foo${i}`),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function main({ n, type, arrayLength }) {
|
||||
const [validate, value] = getValidateFactory(type, arrayLength);
|
||||
|
||||
// Warm up.
|
||||
const length = 1024;
|
||||
const array = [];
|
||||
for (let i = 0; i < length; ++i) {
|
||||
array.push(validate(value));
|
||||
}
|
||||
|
||||
bench.start();
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const index = i % length;
|
||||
array[index] = validate(value);
|
||||
}
|
||||
|
||||
bench.end(n);
|
||||
|
||||
// Verify the entries to prevent dead code elimination from making
|
||||
// the benchmark invalid.
|
||||
for (let i = 0; i < length; ++i) {
|
||||
assert.strictEqual(typeof array[i], 'undefined');
|
||||
}
|
||||
}
|
|
@ -311,8 +311,12 @@ const validateArray = hideStackFrames((value, name, minLength = 0) => {
|
|||
/** @type {validateStringArray} */
|
||||
function validateStringArray(value, name) {
|
||||
validateArray(value, name);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
validateString(value[i], `${name}[${i}]`);
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
// Don't use validateString here for performance reasons, as
|
||||
// we would generate intermediate strings for the name.
|
||||
if (typeof value[i] !== 'string') {
|
||||
throw new ERR_INVALID_ARG_TYPE(`${name}[${i}]`, 'string', value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,8 +330,12 @@ function validateStringArray(value, name) {
|
|||
/** @type {validateBooleanArray} */
|
||||
function validateBooleanArray(value, name) {
|
||||
validateArray(value, name);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
validateBoolean(value[i], `${name}[${i}]`);
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
// Don't use validateBoolean here for performance reasons, as
|
||||
// we would generate intermediate strings for the name.
|
||||
if (value[i] !== true && value[i] !== false) {
|
||||
throw new ERR_INVALID_ARG_TYPE(`${name}[${i}]`, 'boolean', value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ require('../common');
|
|||
|
||||
// Minimal test for assert benchmarks. This makes sure the benchmarks aren't
|
||||
// completely broken but nothing more than that.
|
||||
|
||||
const runBenchmark = require('../common/benchmark');
|
||||
|
||||
runBenchmark('validators');
|
||||
|
|
Loading…
Reference in New Issue