Skip to content

Commit 2c9e4c9

Browse files
Giovanni BucciMesteery
authored andcommitted
benchmark: adds groups to better separate benchmarks
Fixes: #26425 Co-Authored-By: Yaman Kassir <mestery@protonmail.com> PR-URL: #54393 Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
1 parent 3f753d8 commit 2c9e4c9

4 files changed

Lines changed: 89 additions & 27 deletions

File tree

‎benchmark/common.js‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,36 @@ class Benchmark {
2222
this.name=require.main.filename.slice(__dirname.length+1);
2323

2424
// Execution arguments i.e. flags used to run the jobs
25-
this.flags=process.env.NODE_BENCHMARK_FLAGS ?
26-
process.env.NODE_BENCHMARK_FLAGS.split(/\s+/) :
27-
[];
25+
this.flags=process.env.NODE_BENCHMARK_FLAGS?.split(/\s+/)??[];
2826

2927
// Parse job-specific configuration from the command line arguments
3028
constargv=process.argv.slice(2);
3129
constparsed_args=this._parseArgs(argv,configs,options);
30+
3231
this.options=parsed_args.cli;
3332
this.extra_options=parsed_args.extra;
33+
this.combinationFilter=typeofoptions.combinationFilter==='function' ? options.combinationFilter : allow;
34+
35+
if(options.byGroups){
36+
this.queue=[];
37+
constgroupNames=process.env.NODE_RUN_BENCHMARK_GROUPS?.split(',')??Object.keys(configs);
38+
39+
for(constgroupNameofgroupNames){
40+
constconfig={ ...configs[groupName][0],group: groupName};
41+
constparsed_args=this._parseArgs(argv,config,options);
42+
43+
this.options=parsed_args.cli;
44+
this.extra_options=parsed_args.extra;
45+
this.queue=this.queue.concat(this._queue(this.options));
46+
}
47+
}else{
48+
this.queue=this._queue(this.options);
49+
}
50+
3451
if(options.flags){
3552
this.flags=this.flags.concat(options.flags);
3653
}
3754

38-
if(typeofoptions.combinationFilter==='function')
39-
this.combinationFilter=options.combinationFilter;
40-
else
41-
this.combinationFilter=allow;
42-
43-
// The configuration list as a queue of jobs
44-
this.queue=this._queue(this.options);
45-
4655
if(this.queue.length===0)
4756
return;
4857

‎benchmark/http/headers.js‎

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,32 @@ const common = require('../common.js');
44
consthttp=require('http');
55

66
constbench=common.createBenchmark(main,{
7-
n: [10,600],
8-
len: [1,100],
9-
duration: 5,
10-
});
7+
fewHeaders: {
8+
n: [10],
9+
len: [1,5],
10+
duration: 5,
11+
},
12+
mediumHeaders: {
13+
n: [50],
14+
len: [1,10],
15+
duration: 5,
16+
},
17+
manyHeaders: {
18+
n: [600],
19+
len: [1,100],
20+
duration: 5,
21+
},
22+
},{byGroups: true});
1123

1224
functionmain({ len, n, duration }){
1325
constheaders={
1426
'Connection': 'keep-alive',
1527
'Transfer-Encoding': 'chunked',
1628
};
1729

18-
// TODO(BridgeAR): Change this benchmark to use grouped arguments when
19-
// implemented. https://github.com/nodejs/node/issues/26425
20-
constIs=[ ...Array(Math.max(n/len,1)).keys()];
21-
constJs=[ ...Array(len).keys()];
30+
constIs=[...Array(n/len).keys()];
31+
constJs=[...Array(len).keys()];
32+
2233
for(constiofIs){
2334
headers[`foo${i}`]=Js.map(()=>`some header value ${i}`);
2435
}
@@ -27,6 +38,7 @@ function main({ len, n, duration }) {
2738
res.writeHead(200,headers);
2839
res.end();
2940
});
41+
3042
server.listen(0,()=>{
3143
bench.http({
3244
path: '/',

‎doc/contributing/writing-and-running-benchmarks.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,19 @@ process/bench-env.js operation="query" n=1000000: 3,625,787.2150573144
272272
process/bench-env.js operation="delete" n=1000000: 1,521,131.5742806569
273273
```
274274

275+
#### Grouping benchmarks
276+
277+
Benchmarks can also have groups, giving the developer greater flexibility in differentiating between test cases
278+
and also helping reduce the time to run the combination of benchmark parameters.
279+
280+
By default, all groups are executed when running the benchmark.
281+
However, it is possible to specify individual groups by setting the
282+
`NODE_RUN_BENCHMARK_GROUPS` environment variable when running `compare.js`:
283+
284+
```bash
285+
NODE_RUN_BENCHMARK_GROUPS=fewHeaders,manyHeaders node http/headers.js
286+
```
287+
275288
### Comparing Node.js versions
276289

277290
To compare the effect of a new Node.js version use the `compare.js` tool. This
@@ -492,6 +505,23 @@ The arguments of `createBenchmark` are:
492505
*`options` {Object} The benchmark options. Supported options:
493506
*`flags` {Array} Contains node-specific command line flags to pass to
494507
the child process.
508+
509+
*`byGroups` {Boolean} option for processing `configs` by groups:
510+
```js
511+
constbench=common.createBenchmark(main, {
512+
groupA: {
513+
source: ['array'],
514+
len: [10, 2048],
515+
n: [50],
516+
},
517+
groupB: {
518+
source: ['buffer', 'string'],
519+
len: [2048],
520+
n: [50, 2048],
521+
},
522+
}, { byGroups:true });
523+
```
524+
495525
*`combinationFilter` {Function} Has a single parameter which is an object
496526
containing a combination of benchmark parameters. It should return`true`
497527
or `false` to indicate whether the combination should be included or not.

‎test/common/benchmark.js‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,27 @@ function runBenchmark(name, env) {
2727
child.on('exit',(code,signal)=>{
2828
assert.strictEqual(code,0);
2929
assert.strictEqual(signal,null);
30+
3031
// This bit makes sure that each benchmark file is being sent settings such
3132
// that the benchmark file runs just one set of options. This helps keep the
32-
// benchmark tests from taking a long time to run. Therefore, each benchmark
33-
// file should result in three lines of output: a blank line, a line with
34-
// the name of the benchmark file, and a line with the only results that we
35-
// get from testing the benchmark file.
36-
assert.ok(
37-
/^(?:\n.+?\n.+?\n)+$/.test(stdout),
38-
`benchmark file not running exactly one configuration in test: ${stdout}`,
39-
);
33+
// benchmark tests from taking a long time to run. Therefore, stdout should be composed as follows:
34+
// The first and last lines should be empty.
35+
// Each test should be separated by a blank line.
36+
// The first line of each test should contain the test's name.
37+
// The second line of each test should contain the configuration for the test.
38+
// If the test configuration is not a group, there should be exactly two lines.
39+
// Otherwise, it is possible to have more than two lines.
40+
41+
constsplitTests=stdout.split(/\n\s*\n/);
42+
43+
for(lettestIdx=1;testIdx<splitTests.length-1;testIdx++){
44+
constlines=splitTests[testIdx].split('\n');
45+
assert.ok(/.+/.test(lines[0]));
46+
47+
if(!lines[1].includes('group="')){
48+
assert.strictEqual(lines.length,2,`benchmark file not running exactly one configuration in test: ${stdout}`);
49+
}
50+
}
4051
});
4152
}
4253

0 commit comments

Comments
 (0)