Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions packages/js-krauset/package.json
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
{
"name": "js-framework-benchmark-react-supergrain",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build-prod": "vite build",
"typecheck": "tsc --noEmit",
"test": "pnpm build-prod && vitest run --config vitest.dist.config.ts src/dist.test.ts",
"test:perf": "pnpm build-prod && vitest run --config vitest.dist.config.ts src/perf.test.ts --reporter=verbose 2>&1 | tee perf-results.txt",
"perf:stats": "node perf-stats.ts",
"perf:compare": "node perf-compare.ts",
"perf:profile": "pnpm build-prod && PROFILE=1 vitest run --config vitest.dist.config.ts src/perf.test.ts",
"perf:analyze": "node perf-profile.ts"
},
"dependencies": {
"@supergrain/kernel": "workspace:*",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@rollup/plugin-strip": "^3.0.4",
"@types/node": "^22.18.3",
"@types/ramda": "^0.31.1",
"@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^4.7.0",
"@vitest/browser": "4.1.0",
"playwright": "^1.55.0",
"ramda": "^0.32.0",
"typescript": "^5.9.2",
"vite": "^7.1.5",
"vite-plugin-dts": "^4.5.4",
"vitest": "4.1.0"
},
"js-framework-benchmark": {
"frameworkVersionFromPackage": "react",
"frameworkHomeURL": "https://reactjs.org/"
}
"name": "js-framework-benchmark-react-supergrain",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build-prod": "vite build",
"typecheck": "tsc --noEmit",
"test": "pnpm build-prod && vitest run --config vitest.dist.config.ts src/dist.test.ts",
"test:perf": "pnpm build-prod && vitest run --config vitest.dist.config.ts src/perf.test.ts --reporter=verbose 2>&1 | tee perf-results.txt",
"perf:stats": "npx tsx perf-stats.ts",
"perf:compare": "npx tsx perf-compare.ts",
"perf:profile": "pnpm build-prod && PROFILE=1 vitest run --config vitest.dist.config.ts src/perf.test.ts",
Comment on lines +10 to +13
"perf:analyze": "node perf-profile.ts"
},
"dependencies": {
"@supergrain/kernel": "workspace:*",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@rollup/plugin-strip": "^3.0.4",
"@types/node": "^22.18.3",
"@types/ramda": "^0.31.1",
"@types/react": "^19.1.13",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^4.7.0",
"@vitest/browser": "4.1.0",
"playwright": "^1.55.0",
"ramda": "^0.32.0",
"typescript": "^5.9.2",
"vite": "^7.1.5",
"vite-plugin-dts": "^4.5.4",
"vitest": "4.1.0"
},
"js-framework-benchmark": {
"frameworkVersionFromPackage": "react",
"frameworkHomeURL": "https://reactjs.org/"
}
Comment on lines +2 to +39
}
8 changes: 5 additions & 3 deletions packages/js-krauset/perf-compare.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { readFileSync } from "fs";
import { resolve } from "path";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";

const dir = import.meta.dirname;
const __dirname = dirname(fileURLToPath(import.meta.url));
const dir = __dirname;
const args = process.argv.slice(2);

if (args.length !== 2) {
Expand Down Expand Up @@ -49,7 +51,7 @@ function fmtPct(base: number, comp: number): string {
}

console.log(
`\n${baselineName} (${baseline.runCount} runs) vs ${compareName} (${compare.runCount} runs)\n`,
`\n${baselineName} (${baseline.runCount} runs, n=${baseline.effectiveN ?? baseline.runCount}) vs ${compareName} (${compare.runCount} runs, n=${compare.effectiveN ?? compare.runCount})\n`,
);

const header =
Expand Down
39 changes: 29 additions & 10 deletions packages/js-krauset/perf-stats.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import { execSync } from "child_process";
import { readFileSync, readdirSync, writeFileSync } from "fs";
import { resolve } from "path";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";

const __dirname = dirname(fileURLToPath(import.meta.url));

const name = process.argv[2];
const runCount = parseInt(process.argv[3] || "15", 10);
// --trim N: drop N lowest and N highest values per metric before computing
// stats. Requires runCount > 2*N. Default 0 (no trimming).
const trimArg = process.argv.indexOf("--trim");
const trimCount = trimArg !== -1 ? parseInt(process.argv[trimArg + 1] || "0", 10) : 0;
Comment on lines 8 to +13

if (!name) {
console.error("Usage: pnpm perf:stats <name> [runs]");
console.error(" e.g. pnpm perf:stats baseline 15");
console.error("Usage: pnpm perf:stats <name> [runs] [--trim N]");
console.error(" e.g. pnpm perf:stats baseline 20 --trim 3");
process.exit(1);
}

const dir = resolve(import.meta.dirname);
if (trimCount > 0 && runCount <= 2 * trimCount) {
console.error(`Error: runCount (${runCount}) must be greater than 2*trim (${2 * trimCount})`);
process.exit(1);
}

const dir = __dirname;

// Note existing files so we only use the ones we create
const existingFiles = new Set(
Expand Down Expand Up @@ -49,12 +61,17 @@ const numericKeys = [
"domNodesDelta",
];

function stats(values: number[]) {
const sorted = [...values].sort((a, b) => a - b);
function stats(values: number[], trim = 0) {
let trimmed = values;
if (trim > 0) {
const sorted = [...values].sort((a, b) => a - b);
trimmed = sorted.slice(trim, sorted.length - trim);
}
const sorted = [...trimmed].sort((a, b) => a - b);
const n = sorted.length;
const mean = values.reduce((s, v) => s + v, 0) / n;
const mean = trimmed.reduce((s, v) => s + v, 0) / n;
const median = n % 2 === 1 ? sorted[Math.floor(n / 2)] : (sorted[n / 2 - 1] + sorted[n / 2]) / 2;
const stddev = Math.sqrt(values.reduce((s, v) => s + (v - mean) ** 2, 0) / n);
const stddev = Math.sqrt(trimmed.reduce((s, v) => s + (v - mean) ** 2, 0) / n);
return { mean, median, stddev, min: sorted[0], max: sorted[n - 1] };
}

Expand All @@ -63,6 +80,8 @@ const benchmarkNames = runs[0].results.map((r: any) => r.name);
const output: any = {
name,
runCount: newFiles.length,
trimCount,
effectiveN: newFiles.length - 2 * trimCount,
files: newFiles,
git: runs[0].git,
benchmarks: {} as any,
Expand All @@ -72,15 +91,15 @@ for (const benchName of benchmarkNames) {
const samples = runs.map((run: any) => run.results.find((r: any) => r.name === benchName));
const benchmark: any = {};
for (const key of numericKeys) {
benchmark[key] = stats(samples.map((s: any) => s[key]));
benchmark[key] = stats(samples.map((s: any) => s[key]), trimCount);
}
output.benchmarks[benchName] = benchmark;
}

const totalSamples = runs.map((run: any) => run.totals);
output.totals = {} as any;
for (const key of numericKeys.filter((k) => k in runs[0].totals)) {
output.totals[key] = stats(totalSamples.map((t: any) => t[key]));
output.totals[key] = stats(totalSamples.map((t: any) => t[key]), trimCount);
}

const outPath = resolve(dir, `perf-stats-${name}.json`);
Expand Down
9 changes: 4 additions & 5 deletions packages/js-krauset/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ export default defineConfig({
}),
],

// This is the key change:
// We use aliasing to tell Vite to bundle the local supergrain packages
// directly from their source code. This makes the package self-contained
// and removes the need for a pnpm workspace when you copy this package.
resolve: {
alias: {
"@supergrain/kernel": resolve(__dirname, "../kernel/src/index.ts"),
// More specific aliases must come first — Vite uses first-match prefix
// semantics, so subpath aliases must precede the base package alias.
"@supergrain/kernel/react": resolve(__dirname, "../kernel/src/react/index.ts"),
"@supergrain/kernel/internal": resolve(__dirname, "../kernel/src/internal.ts"),
"@supergrain/kernel": resolve(__dirname, "../kernel/src/index.ts"),
},
},

Expand Down
Loading
Loading