Skip to content

Commit

Permalink
lib: improve performance of validateStringArray and validateBooleanArray
Browse files Browse the repository at this point in the history
PR-URL: nodejs#49756
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
  • Loading branch information
Uzlopak authored and alexfernandez committed Nov 1, 2023
1 parent 45e3e91 commit 2f8bbda
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 5 deletions.
61 changes: 61 additions & 0 deletions benchmark/validators/parse-file-mode.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
68 changes: 68 additions & 0 deletions benchmark/validators/validate-array.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
55 changes: 55 additions & 0 deletions benchmark/validators/validate-boolean.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
59 changes: 59 additions & 0 deletions benchmark/validators/validate-encoding.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
69 changes: 69 additions & 0 deletions benchmark/validators/validate-one-of.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
66 changes: 66 additions & 0 deletions benchmark/validators/validate-x-array.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
Loading

0 comments on commit 2f8bbda

Please sign in to comment.