-
-
Notifications
You must be signed in to change notification settings - Fork 36.7k
Expand file tree
/
Copy pathscatter-node-bench.js
More file actions
131 lines (122 loc) Β· 4.29 KB
/
Copy pathscatter-node-bench.js
File metadata and controls
131 lines (122 loc) Β· 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
'use strict';
const CLI = require('./_cli.js');
const {
analyzeScatter,
validateScatterParameters,
} = require('./_node-bench-analysis.js');
const {
csvEncode,
parseInteger,
runBenchmark,
} = require('./_node-bench.js');
const cli = new CLI(`usage: ./node scatter-node-bench.js [options] [--] <file>
Run an explicit node:bench file repeatedly and output each independent
observation with its benchmark parameters as CSV, or summarize the results
directly with --analyze.
--node ./node Node.js binary
--runs 30 number of observations
--warmup 0 warmup samples before each observation
--name-pattern pattern only run matching benchmarks
--node-arg argument pass an argument to the binary (repeatable)
--analyze print a statistical summary instead of CSV
--xaxis parameter parameter to group by with --analyze (required)
--category parameter optional second grouping parameter
--no-chart omit the analysis bar chart
`, {
arrayArgs: ['node-arg'],
boolArgs: ['analyze', 'no-chart'],
});
if (cli.items.length !== 1) cli.abort(cli.usage);
if (cli.optional.analyze && cli.optional.xaxis === undefined) {
cli.abort('--analyze requires --xaxis <parameter>');
}
async function main() {
const runs = parseInteger(cli.optional.runs, 30, '--runs', 1);
const warmup = parseInteger(cli.optional.warmup, 0, '--warmup', 0);
const options = {
namePattern: cli.optional['name-pattern'],
nodeArgs: cli.optional['node-arg'],
warmup,
};
const binary = cli.optional.node || process.execPath;
const rows = [];
const paramNames = new Set();
const csvGroups = new Map();
let expectedIdentities;
let logicalIdentity;
for (let run = 0; run < runs; run++) {
const samples = await runBenchmark(binary, cli.items[0], options);
if (run === 0 && cli.optional.analyze) {
validateScatterParameters(
samples, cli.optional.xaxis, cli.optional.category);
}
const identities = new Set();
for (const sample of samples) {
if (logicalIdentity !== undefined &&
logicalIdentity !== sample.logicalIdentity) {
throw new Error(
'scatter-node-bench.js requires one logical benchmark name per file',
);
}
logicalIdentity = sample.logicalIdentity;
if (identities.has(sample.identity)) {
throw new Error(`Benchmark '${sample.name}' was reported more than once`);
}
identities.add(sample.identity);
const csvGroup = JSON.stringify([sample.name, sample.params]);
const groupedIdentity = csvGroups.get(csvGroup);
if (groupedIdentity !== undefined &&
groupedIdentity !== sample.identity) {
throw new Error(
`Distinct benchmarks would share the CSV group '${sample.name}'`,
);
}
csvGroups.set(csvGroup, sample.identity);
rows.push({ ...sample, observation: run });
for (const name of Object.keys(sample.params)) paramNames.add(name);
}
if (expectedIdentities === undefined) {
expectedIdentities = identities;
} else if (identities.size !== expectedIdentities.size ||
![...identities].every((id) => expectedIdentities.has(id))) {
throw new Error('The set of reported benchmarks changed between runs');
}
}
if (rows.length === 0) {
throw new Error('No benchmark samples were produced');
}
const params = [...paramNames].sort();
if (cli.optional.analyze) {
const output = analyzeScatter(
rows,
cli.optional.xaxis,
cli.optional.category,
!cli.optional['no-chart'],
);
process.stdout.write(output);
return;
}
for (const name of params) {
if (name === 'filename' || name === 'rate' || name === 'time') {
throw new Error(`Benchmark parameter '${name}' is reserved in scatter CSV`);
}
}
const header = ['filename', ...params, 'rate', 'time']
.map(csvEncode)
.join(',');
const output = [header];
for (const row of rows) {
const values = [
csvEncode(row.name),
...params.map((name) => csvEncode(row.params[name] ?? '')),
row.rate,
row.duration,
];
output.push(values.join(','));
}
process.stdout.write(`${output.join('\n')}\n`);
}
main().catch((error) => {
console.error(error.stack);
process.exitCode = 1;
});