Skip to content
This repository has been archived by the owner on Nov 29, 2023. It is now read-only.

Commit

Permalink
Attempt to report summaries to PR
Browse files Browse the repository at this point in the history
Also bumps actions versions which have been warning about Node 12 for no apparent reason
  • Loading branch information
eyelidlessness committed Feb 22, 2023
1 parent fdb904c commit 77eb952
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 76 deletions.
35 changes: 24 additions & 11 deletions .github/workflows/npmjs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,32 @@ on:
jobs:
build:
runs-on: ubuntu-latest
permissions:
pull-requests: write
strategy:
matrix:
target: ['node']
target: ['Node']
node: ['14', '16']
include:
- target: web
- target: Web
node: 16
browser: firefox
- target: web
browser: Firefox
- target: Web
node: 16
browser: chromium
- target: web
browser: Chromium
- target: Web
node: 16
browser: webkit
browser: WebKit
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: cache
with:
path: |
node_modules
~/.cache/ms-playwright
key: ${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
registry-url: https://registry.npmjs.org/
Expand All @@ -43,7 +45,18 @@ jobs:
- if: matrix.node == '16' && matrix.browser == 'webkit'
run: sudo npx playwright install-deps
- run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm test
- run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm run benchmarks
- id: benchmarks
run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm run benchmarks
- uses: marocchino/sticky-pull-request-comment@v2
if: matrix.target == 'Node'
with:
header: Node ${{ matrix.node }}
path: ./.benchmarks.md
- uses: marocchino/sticky-pull-request-comment@v2
if: matrix.target == 'Web'
with:
header: ${{ matrix.browser}}
path: ./.benchmarks.md
- if: github.event_name == 'release' && github.event.action == 'published' && matrix.node == '16' && matrix.target == 'node'
run: npm publish
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Thumbs.db
test-coverage
coverage.shield.badge.md
dist
.benchmarks.md
5 changes: 3 additions & 2 deletions config/build.shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { createHash } from 'crypto';
import { readFileSync } from 'fs';
import pkg from '../package.json';

export const ENV = process.env.ENV?.toLowerCase() === 'web' ? 'web' : 'node';
export const TARGET_ENV =
process.env.ENV?.toLowerCase() === 'web' ? 'web' : 'node';

const md5 = (message: string | Buffer) => {
const hash = createHash('md5');
Expand Down Expand Up @@ -30,6 +31,6 @@ const BROWSER =
export const define = {
PACKAGE_VERSION: JSON.stringify(PACKAGE_VERSION),
VERSION: JSON.stringify(VERSION),
ENV: JSON.stringify(ENV),
ENV: JSON.stringify(TARGET_ENV),
BROWSER: JSON.stringify(BROWSER),
};
127 changes: 66 additions & 61 deletions test/benchmarks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Suite } from 'benchmark';
import type Benchmark from 'benchmark';
import { writeFileSync } from 'fs';
import { setFlagsFromString } from 'v8';
import { runInNewContext } from 'vm';
import { writeFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { setup } from './web/setup';

if (ENV === 'web') {
Expand Down Expand Up @@ -107,70 +108,69 @@ for await (const suite of suites.values()) {
await runSuite(suite);
}

const { GITHUB_STEP_SUMMARY } = process.env;
const SUMMARY_PATH = fileURLToPath(
new URL('../.benchmarks.md', import.meta.url)
);

if (GITHUB_STEP_SUMMARY) {
const sum = (ns: number[]) => ns.reduce((acc, n) => acc + n, 0);
const avg = (ns: number[]) => sum(ns) / ns.length;

const benchmarks = [...suites.values()]
.flatMap((suite): Benchmark[] => suite.slice(0, suite.length))
.filter((benchmark) => benchmark.name !== RELOAD_WORKAROUND)
.sort((a, b) => a.hz - b.hz);

const times = benchmarks.map(({ times }) => times!.elapsed);
const time = sum(times).toFixed(2);
const means = benchmarks.map(({ stats }) => stats.mean * 1000);
const average = avg(means);
const nonOutlierIndex = Math.max(
means.findIndex((mean, index) => {
if (index === 0 || index > means.length - 2) {
return false;
}
const sum = (ns: number[]) => ns.reduce((acc, n) => acc + n, 0);
const avg = (ns: number[]) => sum(ns) / ns.length;

const benchmarks = [...suites.values()]
.flatMap((suite): Benchmark[] => suite.slice(0, suite.length))
.filter((benchmark) => benchmark.name !== RELOAD_WORKAROUND)
.sort((a, b) => a.hz - b.hz);

const times = benchmarks.map(({ times }) => times!.elapsed);
const time = sum(times).toFixed(2);
const means = benchmarks.map(({ stats }) => stats.mean * 1000);
const average = avg(means);
const nonOutlierIndex = Math.max(
means.findIndex((mean, index) => {
if (index === 0 || index > means.length - 2) {
return false;
}

const previous = means[index - 1];
const next = means[index + 1];
const previous = means[index - 1];
const next = means[index + 1];

return (
previous / average > (mean / average) * 2 &&
mean / average <= (next / average) * 2
);
}),
0
);
const averageWithoutOutliers = avg(means.slice(nonOutlierIndex));

/**
* Roughly based on {@link https://github.com/bestiejs/benchmark.js/blob/42f3b732bac3640eddb3ae5f50e445f3141016fd/benchmark.js#L1525}, simplified and modified to output a GitHub Actions summary.
*/
const summaries = benchmarks.map((bench, index) => {
const { error, name, stats } = bench;
let result = error?.message;

if (result == null) {
const size = stats.sample.length;
const mean = `${means[index].toFixed(2)} ms`;

const [hzWhole, hzFractional] = String(
bench.hz.toFixed(bench.hz < 100 ? 2 : 0)
).split('.');
const hz =
hzWhole.replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
(hzFractional ? `.${hzFractional}` : '');
const rme = ${stats.rme.toFixed(2)}%`;
const samples = `${size} run${size === 1 ? '' : 's'}`;

result = `${mean} (${hz} ops/s ${rme}, ${samples})`;
}
return (
previous / average > (mean / average) * 2 &&
mean / average <= (next / average) * 2
);
}),
0
);
const averageWithoutOutliers = avg(means.slice(nonOutlierIndex));

return [name, result];
});
const [slowest] = summaries;
const fastest = summaries[summaries.length - 1];
/**
* Roughly based on {@link https://github.com/bestiejs/benchmark.js/blob/42f3b732bac3640eddb3ae5f50e445f3141016fd/benchmark.js#L1525}, simplified and modified to output a GitHub Actions summary.
*/
const summaries = benchmarks.map((bench, index) => {
const { error, name, stats } = bench;
let result = error?.message;

if (result == null) {
const size = stats.sample.length;
const mean = `${means[index].toFixed(2)} ms`;

const [hzWhole, hzFractional] = String(
bench.hz.toFixed(bench.hz < 100 ? 2 : 0)
).split('.');
const hz =
hzWhole.replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
(hzFractional ? `.${hzFractional}` : '');
const rme = ${stats.rme.toFixed(2)}%`;
const samples = `${size} run${size === 1 ? '' : 's'}`;

result = `${mean} (${hz} ops/s ${rme}, ${samples})`;
}

const summary = /* html */ `
<h1>Benchmarks</h1>
return [name, result];
});
const [slowest] = summaries;
const fastest = summaries[summaries.length - 1];

const summary = /* html */ `
<table>
<tr>
<th></th>
Expand Down Expand Up @@ -218,9 +218,14 @@ if (GITHUB_STEP_SUMMARY) {
</table>
</details>
`
.trim()
.replace(/(^|\n)\s+/g, '$1');
.trim()
.replace(/(^|\n)\s+/g, '$1');

writeFileSync(SUMMARY_PATH, summary);

const { GITHUB_STEP_SUMMARY } = process.env;

if (GITHUB_STEP_SUMMARY != null) {
writeFileSync(GITHUB_STEP_SUMMARY, summary);
}

Expand Down
4 changes: 2 additions & 2 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import type { LibraryFormats } from 'vite';
import type { UserConfig } from 'vitest/config';
import { defineConfig } from 'vitest/config';
import config from './config/config.json';
import { define, ENV } from './config/build.shared';
import { define, TARGET_ENV } from './config/build.shared';

export default defineConfig(async () => {
const isWeb = ENV === 'web';
const isWeb = TARGET_ENV === 'web';
const entryNames = isWeb ? ['transformer'] : ['app', 'transformer'];
const entry = entryNames.map((name) =>
resolve(__dirname, `./src/${name}.ts`)
Expand Down

0 comments on commit 77eb952

Please sign in to comment.