Skip to content

Commit

Permalink
chore(perf): save summary table to files and improve readme @W-177187…
Browse files Browse the repository at this point in the history
…70 (#5179)

* chore: document format script

* chore(perf): save tachometer results summary to MD and HTML files @W-17718770
  • Loading branch information
wjhsf authored Jan 31, 2025
1 parent 8eec50f commit 61020f9
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 52 deletions.
13 changes: 11 additions & 2 deletions packages/@lwc/perf-benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@ Then run the benchmarks:
yarn test:performance
```

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`.

To recreate the summary tables without re-running the full test suite, ensure the JSON files exist do:

```shell
cd packages/@lwc/perf-benchmarks
yarn test:format
```

To run an individual benchmark, do:

```shell
cd packages/@lwc/perf-benchmarks
../../../node_modules/.bin/tach --config dist/__benchmarks__/path/to/tachometer.json
yarn tach --config dist/__benchmarks__/path/to/tachometer.json
```

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

```shell
cd packages/@lwc/perf-benchmarks
../../../node_modules/.bin/tach --manual --config dist/__benchmarks__/path/to/tachometer.json
yarn tach --manual --config dist/__benchmarks__/path/to/tachometer.json
```

This will print out the URLs you can use to test manually.
Expand Down
120 changes: 70 additions & 50 deletions packages/@lwc/perf-benchmarks/scripts/format-results.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
* Forms the JSON results from multiple Tachometer runs and outputs a Markdown table of results.
*/

import fs from 'fs/promises';
import fsp from 'node:fs/promises';
import path from 'node:path';
import { markdownTable } from 'markdown-table';

const OUT_DIR = path.resolve(import.meta.dirname, '../dist/__benchmarks__');

function avg(a, b) {
return (a + b) / 2;
}
Expand All @@ -20,56 +23,73 @@ function fmt(num) {
return num.toFixed(2);
}

async function main() {
const jsonFiles = [...process.argv].filter((_) => _.endsWith('.json'));
const header = [
'Benchmark',
'Before (low)',
'Before (high)',
'Before (avg)',
'After (low)',
'After (high)',
'After (avg)',
'Delta (low)',
'Delta (high)',
'Delta (avg)',
'Delta perc (low)',
'Delta perc (high)',
'Delta perc (avg)',
];

const results = await Promise.all(
jsonFiles.map(async (file) => {
const json = JSON.parse(await fs.readFile(file, 'utf8'));
const { benchmarks } = json;
const { low: deltaAbsLow, high: deltaAbsHigh } = benchmarks[0].differences[1].absolute;
const { low: deltaPercLow, high: deltaPercHigh } =
benchmarks[0].differences[1].percentChange;
const { low: beforeLow, high: beforeHigh } = benchmarks[1].mean;
const { low: afterLow, high: afterHigh } = benchmarks[0].mean;
const benchmarkName = benchmarks[0].name.replace('-this-change', '');
return [
benchmarkName,
fmt(beforeLow),
fmt(beforeHigh),
fmt(avg(beforeLow, beforeHigh)),
fmt(afterLow),
fmt(afterHigh),
fmt(avg(afterLow, afterHigh)),
fmt(deltaAbsLow),
fmt(deltaAbsHigh),
fmt(avg(deltaAbsLow, deltaAbsHigh)),
fmt(deltaPercLow / 100),
fmt(deltaPercHigh / 100),
fmt(avg(deltaPercLow, deltaPercHigh) / 100),
];
function htmlTable(head, body) {
const thead = `<tr>${head.map((txt) => `<th>${txt}</th>`).join('')}</tr>`;
const tbody = body
.map((row) => {
return `<tr>${row.map((txt) => `<td>${txt}</td>`).join('')}</tr>`;
})
);
.join('');
return `<!DOCTYPE html>
<html><body><table>
<thead>${thead}</thead>
<tbody>${tbody}</tbody>
</table></body></html>`;
}

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

main().catch((err) => {
console.error(err);
process.exit(1);
});
const jsonFiles = [...process.argv].filter((_) => _.endsWith('.json'));
const header = [
'Benchmark',
'Before (low)',
'Before (high)',
'Before (avg)',
'After (low)',
'After (high)',
'After (avg)',
'Delta (low)',
'Delta (high)',
'Delta (avg)',
'Delta perc (low)',
'Delta perc (high)',
'Delta perc (avg)',
];

const results = await Promise.all(
jsonFiles.map(async (file) => {
const json = JSON.parse(await fsp.readFile(file, 'utf8'));
const { benchmarks } = json;
const { low: deltaAbsLow, high: deltaAbsHigh } = benchmarks[0].differences[1].absolute;
const { low: deltaPercLow, high: deltaPercHigh } =
benchmarks[0].differences[1].percentChange;
const { low: beforeLow, high: beforeHigh } = benchmarks[1].mean;
const { low: afterLow, high: afterHigh } = benchmarks[0].mean;
const benchmarkName = benchmarks[0].name.replace('-this-change', '');
return [
benchmarkName,
fmt(beforeLow),
fmt(beforeHigh),
fmt(avg(beforeLow, beforeHigh)),
fmt(afterLow),
fmt(afterHigh),
fmt(avg(afterLow, afterHigh)),
fmt(deltaAbsLow),
fmt(deltaAbsHigh),
fmt(avg(deltaAbsLow, deltaAbsHigh)),
fmt(deltaPercLow / 100),
fmt(deltaPercHigh / 100),
fmt(avg(deltaPercLow, deltaPercHigh) / 100),
];
})
);

// Sort by test name
results.sort((a, b) => a[0].localeCompare(b[0]));

const md = markdownTable([header, ...results]);
console.log(md);
await saveResult('results.md', md);
await saveResult('results.html', htmlTable(header, results));

0 comments on commit 61020f9

Please sign in to comment.