Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

benchmark: add "byGroup" config option #26559

Closed
wants to merge 10 commits into from
Closed
110 changes: 110 additions & 0 deletions benchmark/buffers/buffer-from-by-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use strict';

const common = require('../common.js');
const assert = require('assert');
const bench = common.createBenchmark(main, {
groupA: {
source: [
'array',
'arraybuffer',
'arraybuffer-middle',
'buffer',
'uint8array',
'string',
'string-utf8',
'string-base64',
'object',
],
len: [10, 2048],
n: [2048]
},
groupB: {
source: [
'buffer',
'string',
],
len: [2048],
n: [2048]
}
}, { byGroup: true });

function main({ len, n, source }) {
const array = new Array(len).fill(42);
const arrayBuf = new ArrayBuffer(len);
const str = 'a'.repeat(len);
const buffer = Buffer.allocUnsafe(len);
const uint8array = new Uint8Array(len);
const obj = { length: null }; // Results in a new, empty Buffer

let i;

switch (source) {
case 'array':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(array);
}
bench.end(n);
break;
case 'arraybuffer':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(arrayBuf);
}
bench.end(n);
break;
case 'arraybuffer-middle':
const offset = ~~(len / 4);
const length = ~~(len / 2);
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(arrayBuf, offset, length);
}
bench.end(n);
break;
case 'buffer':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(buffer);
}
bench.end(n);
break;
case 'uint8array':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(uint8array);
}
bench.end(n);
break;
case 'string':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(str);
}
bench.end(n);
break;
case 'string-utf8':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(str, 'utf8');
}
bench.end(n);
break;
case 'string-base64':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(str, 'base64');
}
bench.end(n);
break;
case 'object':
bench.start();
for (i = 0; i < n * 1024; i++) {
Buffer.from(obj);
}
bench.end(n);
break;
default:
assert.fail(null, null, 'Should not get here');
}
}
50 changes: 44 additions & 6 deletions benchmark/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,50 @@ exports.createBenchmark = function(fn, configs, options) {
function Benchmark(fn, configs, options) {
// Use the file name as the name of the benchmark
this.name = require.main.filename.slice(__dirname.length + 1);
// Parse job-specific configuration from the command line arguments
const parsed_args = this._parseArgs(process.argv.slice(2), configs);
this.options = parsed_args.cli;
this.extra_options = parsed_args.extra;
// The configuration list as a queue of jobs
this.queue = this._queue(this.options);
this.queue = [];
const byGroup = (options && options.byGroup) || false;

const enqueueConfigsInFirstGroup = (configs) => {
const firstGroupKey = Object.keys(configs)[0];
const configsInFirstGroup = configs[firstGroupKey];
const parsedArgs =
this._parseArgs(process.argv.slice(2), configsInFirstGroup);
this.options = parsedArgs.cli;
this.extra_options = parsedArgs.extra;
this.queue = this._queue(this.options);
};

const enqueueConfigsInGroups = (configs) => {
for (const groupKey of Object.keys(configs)) {
const config = configs[groupKey];
const parsedArgs = this._parseArgs(process.argv.slice(2), config);
this.options = parsedArgs.cli;
this.extra_options = parsedArgs.extra;
// The configuration list as a queue of jobs by merging the existing
// items with the new items to return a new array
this.queue = [ ...this.queue, ...this._queue(this.options) ];
}
};

const enqueueConfigs = (configs) => {
// Parse job-specific configuration from the command line arguments
const parsedArgs = this._parseArgs(process.argv.slice(2), configs);
this.options = parsedArgs.cli;
this.extra_options = parsedArgs.extra;
// The configuration list as a queue of jobs
this.queue = this._queue(this.options);
};

if (byGroup) {
if (process.env.NODEJS_BENCHMARK_BYPASS_GROUP) {
enqueueConfigsInFirstGroup(configs);
} else {
enqueueConfigsInGroups(configs);
}
} else {
enqueueConfigs(configs);
}
Copy link
Member

@lundibundi lundibundi Feb 9, 2020

Choose a reason for hiding this comment

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

I think this can be simplified to

const parseConfig = (config) => {
  const parsedArgs = this._parseArgs(process.argv.slice(2), config);
  this.options = parsedArgs.cli;
  this.extra_options = parsedArgs.extra;
  this.queue = [ ...this.queue, ...this._queue(this.options) ];
}

if (byGroup) {
  let usedConfigs = Object.values(configs);
  if (process.env.NODEJS_BENCHMARK_BYPASS_GROUP)
    usedConfigs = usedConfigs[0];
  usedConfigs.forEach(parseConfig);
} else {
  parseConfig(configs);
}


// The configuration of the current job, head of the queue
this.config = this.queue[0];
// Execution arguments i.e. flags used to run the jobs
Expand Down
21 changes: 19 additions & 2 deletions doc/guides/writing-and-running-benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,25 @@ The arguments of `createBenchmark` are:
possible combinations of these parameters, unless specified otherwise.
Each configuration is a property with an array of possible values.
Note that the configuration values can only be strings or numbers.
* `options` {Object} The benchmark options. At the moment only the `flags`
option for specifying command line flags is supported.
* `options` {Object} The benchmark options are:

* `flags` option for specifying command line flags is supported
* `byGroup` option for processing `configs` by groups with this syntax:

```js
const bench = common.createBenchmark(main, {
groupA: {
source: ['array'],
len: [10, 2048],
n: [50]
},
groupB: {
source: ['buffer', 'string'],
len: [2048],
n: [50, 2048]
}
}, { byGroup: true });
```

`createBenchmark` returns a `bench` object, which is used for timing
the runtime of the benchmark. Run `bench.start()` after the initialization
Expand Down
5 changes: 4 additions & 1 deletion test/benchmark/test-benchmark-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ runBenchmark('buffers',
'value=0',
'withTotalLength=0'
],
{ NODEJS_BENCHMARK_ZERO_ALLOWED: 1 });
{
NODEJS_BENCHMARK_ZERO_ALLOWED: 1,
NODEJS_BENCHMARK_BYPASS_GROUP: 1
});