Skip to content

Commit 61020f9

Browse files
authored
chore(perf): save summary table to files and improve readme @W-17718770 (#5179)
* chore: document format script * chore(perf): save tachometer results summary to MD and HTML files @W-17718770
1 parent 8eec50f commit 61020f9

File tree

2 files changed

+81
-52
lines changed

2 files changed

+81
-52
lines changed

packages/@lwc/perf-benchmarks/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@ Then run the benchmarks:
1414
yarn test:performance
1515
```
1616

17+
Individual benchmark results are saved in `*.tachometer.results.json` files. A summary table is printed to console and saved as `results.md` and `results.html`.
18+
19+
To recreate the summary tables without re-running the full test suite, ensure the JSON files exist do:
20+
21+
```shell
22+
cd packages/@lwc/perf-benchmarks
23+
yarn test:format
24+
```
25+
1726
To run an individual benchmark, do:
1827

1928
```shell
2029
cd packages/@lwc/perf-benchmarks
21-
../../../node_modules/.bin/tach --config dist/__benchmarks__/path/to/tachometer.json
30+
yarn tach --config dist/__benchmarks__/path/to/tachometer.json
2231
```
2332

2433
> [!TIP]
@@ -30,7 +39,7 @@ When the benchmark is not working, the best way to debug it locally is to load i
3039

3140
```shell
3241
cd packages/@lwc/perf-benchmarks
33-
../../../node_modules/.bin/tach --manual --config dist/__benchmarks__/path/to/tachometer.json
42+
yarn tach --manual --config dist/__benchmarks__/path/to/tachometer.json
3443
```
3544

3645
This will print out the URLs you can use to test manually.

packages/@lwc/perf-benchmarks/scripts/format-results.mjs

Lines changed: 70 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
* Forms the JSON results from multiple Tachometer runs and outputs a Markdown table of results.
1010
*/
1111

12-
import fs from 'fs/promises';
12+
import fsp from 'node:fs/promises';
13+
import path from 'node:path';
1314
import { markdownTable } from 'markdown-table';
1415

16+
const OUT_DIR = path.resolve(import.meta.dirname, '../dist/__benchmarks__');
17+
1518
function avg(a, b) {
1619
return (a + b) / 2;
1720
}
@@ -20,56 +23,73 @@ function fmt(num) {
2023
return num.toFixed(2);
2124
}
2225

23-
async function main() {
24-
const jsonFiles = [...process.argv].filter((_) => _.endsWith('.json'));
25-
const header = [
26-
'Benchmark',
27-
'Before (low)',
28-
'Before (high)',
29-
'Before (avg)',
30-
'After (low)',
31-
'After (high)',
32-
'After (avg)',
33-
'Delta (low)',
34-
'Delta (high)',
35-
'Delta (avg)',
36-
'Delta perc (low)',
37-
'Delta perc (high)',
38-
'Delta perc (avg)',
39-
];
40-
41-
const results = await Promise.all(
42-
jsonFiles.map(async (file) => {
43-
const json = JSON.parse(await fs.readFile(file, 'utf8'));
44-
const { benchmarks } = json;
45-
const { low: deltaAbsLow, high: deltaAbsHigh } = benchmarks[0].differences[1].absolute;
46-
const { low: deltaPercLow, high: deltaPercHigh } =
47-
benchmarks[0].differences[1].percentChange;
48-
const { low: beforeLow, high: beforeHigh } = benchmarks[1].mean;
49-
const { low: afterLow, high: afterHigh } = benchmarks[0].mean;
50-
const benchmarkName = benchmarks[0].name.replace('-this-change', '');
51-
return [
52-
benchmarkName,
53-
fmt(beforeLow),
54-
fmt(beforeHigh),
55-
fmt(avg(beforeLow, beforeHigh)),
56-
fmt(afterLow),
57-
fmt(afterHigh),
58-
fmt(avg(afterLow, afterHigh)),
59-
fmt(deltaAbsLow),
60-
fmt(deltaAbsHigh),
61-
fmt(avg(deltaAbsLow, deltaAbsHigh)),
62-
fmt(deltaPercLow / 100),
63-
fmt(deltaPercHigh / 100),
64-
fmt(avg(deltaPercLow, deltaPercHigh) / 100),
65-
];
26+
function htmlTable(head, body) {
27+
const thead = `<tr>${head.map((txt) => `<th>${txt}</th>`).join('')}</tr>`;
28+
const tbody = body
29+
.map((row) => {
30+
return `<tr>${row.map((txt) => `<td>${txt}</td>`).join('')}</tr>`;
6631
})
67-
);
32+
.join('');
33+
return `<!DOCTYPE html>
34+
<html><body><table>
35+
<thead>${thead}</thead>
36+
<tbody>${tbody}</tbody>
37+
</table></body></html>`;
38+
}
6839

69-
console.log(markdownTable([header, ...results.sort((a, b) => (a[0] < b[0] ? -1 : 1))]));
40+
async function saveResult(filename, content) {
41+
return await fsp.writeFile(path.join(OUT_DIR, filename), content, 'utf8');
7042
}
7143

72-
main().catch((err) => {
73-
console.error(err);
74-
process.exit(1);
75-
});
44+
const jsonFiles = [...process.argv].filter((_) => _.endsWith('.json'));
45+
const header = [
46+
'Benchmark',
47+
'Before (low)',
48+
'Before (high)',
49+
'Before (avg)',
50+
'After (low)',
51+
'After (high)',
52+
'After (avg)',
53+
'Delta (low)',
54+
'Delta (high)',
55+
'Delta (avg)',
56+
'Delta perc (low)',
57+
'Delta perc (high)',
58+
'Delta perc (avg)',
59+
];
60+
61+
const results = await Promise.all(
62+
jsonFiles.map(async (file) => {
63+
const json = JSON.parse(await fsp.readFile(file, 'utf8'));
64+
const { benchmarks } = json;
65+
const { low: deltaAbsLow, high: deltaAbsHigh } = benchmarks[0].differences[1].absolute;
66+
const { low: deltaPercLow, high: deltaPercHigh } =
67+
benchmarks[0].differences[1].percentChange;
68+
const { low: beforeLow, high: beforeHigh } = benchmarks[1].mean;
69+
const { low: afterLow, high: afterHigh } = benchmarks[0].mean;
70+
const benchmarkName = benchmarks[0].name.replace('-this-change', '');
71+
return [
72+
benchmarkName,
73+
fmt(beforeLow),
74+
fmt(beforeHigh),
75+
fmt(avg(beforeLow, beforeHigh)),
76+
fmt(afterLow),
77+
fmt(afterHigh),
78+
fmt(avg(afterLow, afterHigh)),
79+
fmt(deltaAbsLow),
80+
fmt(deltaAbsHigh),
81+
fmt(avg(deltaAbsLow, deltaAbsHigh)),
82+
fmt(deltaPercLow / 100),
83+
fmt(deltaPercHigh / 100),
84+
fmt(avg(deltaPercLow, deltaPercHigh) / 100),
85+
];
86+
})
87+
);
88+
89+
// Sort by test name
90+
results.sort((a, b) => a[0].localeCompare(b[0]));
91+
92+
const md = markdownTable([header, ...results]);
93+
console.log(md);
94+
await saveResult('results.md', md);
95+
await saveResult('results.html', htmlTable(header, results));

0 commit comments

Comments
 (0)