diff --git a/.github/workflows/config-check.yml b/.github/workflows/config-check.yml new file mode 100644 index 0000000..1ff4b00 --- /dev/null +++ b/.github/workflows/config-check.yml @@ -0,0 +1,17 @@ +name: Benchmark Config Drift Check + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + config-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm run config:check diff --git a/CLAUDE.md b/CLAUDE.md index ac0107e..b5839b8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,11 +16,16 @@ The app has two modes: ``` benching_machine/ +├── shared/ +│ └── benchmark-registry.json # CANONICAL config source (hand-edited — see below) +├── scripts/ +│ └── generate-benchmark-config.js # Generates configs.generated.js + benchmarkRegistry.js ├── backend/ │ ├── cli.js # CLI entry point (Commander.js) │ ├── server.js # Optional Express API (port 4000) │ └── benchmarks/ -│ ├── configs.js # MASTER config list + mock runner +│ ├── configs.js # Mock runner logic; imports generated config data +│ ├── configs.generated.js # GENERATED — do not hand-edit │ ├── compilation.js # CLI compilation benchmarks (Benchmark.js) │ ├── cpu.js # CPU benchmarks (Fibonacci, Prime, Matrix) │ ├── memory.js # Memory benchmarks @@ -33,14 +38,17 @@ benching_machine/ ├── src/ │ ├── App.js # React root, state management │ ├── index.js # React entry point +│ ├── generated/ +│ │ └── benchmarkRegistry.js # GENERATED — do not hand-edit │ ├── components/ -│ │ ├── BenchmarkRunner.js # Control panel + config runner (mirrors configs.js) +│ │ ├── BenchmarkRunner.js # Control panel + config runner; imports generated config data │ │ ├── HallwayVisualization.js # View mode switcher (hallway / charts) │ │ ├── Hallway3DView.js # Immersive server rack view │ │ ├── RackUnitDetail.js # Zoomed per-rack unit detail │ │ └── CompilerComparisonView.js # Analytical compiler charts │ └── utils/ │ ├── wasmLoader.js # Dynamic WASM module loader +│ ├── machineProfiles.js # Re-exports generated machineProfiles + helpers │ └── snapshotManager.js # Save/load/diff benchmark snapshots ├── public/ │ ├── webgl-benchmarks.js # WebGL fragment shader compute @@ -114,33 +122,42 @@ npm run build:cheerp ## How to Add a New Compilation Config -1. **`backend/benchmarks/configs.js`** — add an entry to `configurations[]`: - ```js +Benchmark configuration has a **single hand-edited source file**: `shared/benchmark-registry.json`. Backend and frontend both import *generated* modules derived from it — never add configs directly to `backend/benchmarks/configs.js` or `src/components/BenchmarkRunner.js`. + +1. **`shared/benchmark-registry.json`** — add an entry to `configurations[]`: + ```json { - id: 'js_esbuild', - name: 'esbuild', - desc: 'Go-based bundler/minifier', - color: '#ffcc00', - compilation: { - family: 'js', - toolchain: 'esbuild', - backend: 'Go', - language: 'JavaScript', - optLevel: 'minify', - flags: ['--minify', '--bundle'], - postProcess: [], - status: 'simulated', // change to 'real' when artifacts exist - } + "id": "js_esbuild", + "name": "esbuild", + "desc": "Go-based bundler/minifier", + "color": "#ffcc00", + "compilation": { + "family": "js", + "toolchain": "esbuild", + "backend": "Go", + "language": "JavaScript", + "optLevel": "minify", + "flags": ["--minify", "--bundle"], + "postProcess": [], + "status": "simulated" + }, + "multiplier": 1.08 } ``` - Add a case to `getMultiplier()` with a realistic relative value. + `status` is one of `'real' | 'simulated' | 'experimental'`. `multiplier` is the simulation factor used by both the CLI mock runner and the frontend fallback simulation. + +2. **Regenerate**: run `npm run config:generate`. This regenerates: + - `backend/benchmarks/configs.generated.js` (CommonJS, imported by `backend/benchmarks/configs.js`) + - `src/generated/benchmarkRegistry.js` (ESM, imported by `src/components/BenchmarkRunner.js` and `src/utils/machineProfiles.js`) -2. **`src/components/BenchmarkRunner.js`** — mirror the same entry in its local `configurations[]` array (this file is the frontend's copy). + Commit the regenerated files alongside the registry change. `npm run config:check` (run in CI) fails the build if the generated files are stale relative to the registry. 3. **`src/utils/wasmLoader.js`** — if the config loads a WASM artifact, add a `case` for its `id` pointing to the artifact path. 4. **`BENCHMARKS_STATUS.md`** — add a row documenting real vs simulated status. +Hand-editing the config data in `backend/benchmarks/configs.js`, `src/components/BenchmarkRunner.js`, `src/utils/machineProfiles.js`, or either `*.generated.js` file will be overwritten (or caught by `npm run config:check`) the next time the registry is regenerated. + --- ## Data Model @@ -246,7 +263,7 @@ These are not yet in the benchmark suite but are worth adding: ## Common Pitfalls -- **BenchmarkRunner.js duplicates configs.js** — both must be kept in sync when adding new configs. +- **Editing generated files directly** — `backend/benchmarks/configs.generated.js` and `src/generated/benchmarkRegistry.js` are overwritten by `npm run config:generate`. Edit `shared/benchmark-registry.json` instead and regenerate. - **WASM 404s in browser**: `wasmLoader.js` pre-checks file existence; if artifacts aren't built you'll get a silent fallback to simulation. - **SharedArrayBuffer (for threads)**: requires COOP/COEP headers — the dev server in `package.json` scripts sets these via `REACT_APP_*` env or a custom server wrapper. - **WebGPU availability**: only Chrome/Edge 113+. The app checks `navigator.gpu` and disables the GPU button if unavailable. diff --git a/backend/benchmarks/configs.generated.js b/backend/benchmarks/configs.generated.js new file mode 100644 index 0000000..ec8f83d --- /dev/null +++ b/backend/benchmarks/configs.generated.js @@ -0,0 +1,563 @@ +// AUTO-GENERATED by scripts/generate-benchmark-config.js — DO NOT EDIT BY HAND. +// Source of truth: shared/benchmark-registry.json +// Run `npm run config:generate` after editing the registry to refresh this file. + +const configurations = [ + { + "id": "js_inline", + "name": "Inline Script", + "desc": "Standard JS (HTML)", + "color": "#f1e05a", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_external", + "name": "External File", + "desc": "Standard JS (.js)", + "color": "#f0db4f", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_wasm_std", + "name": "JS + WASM", + "desc": "Vanilla WASM Loading", + "color": "#654ff0", + "compilation": { + "family": "wasm", + "toolchain": "WebAssembly.compile()", + "backend": "Browser WASM engine", + "language": "WebAssembly", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "js_terser", + "name": "JS + Terser", + "desc": "Minified & Mangled", + "color": "#fab1a0", + "compilation": { + "family": "js", + "toolchain": "Terser", + "backend": "V8", + "language": "JavaScript", + "optLevel": "minify+mangle", + "flags": [ + "--compress", + "--mangle" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_closure", + "name": "Closure Compiler", + "desc": "Advanced Optimization", + "color": "#e17055", + "compilation": { + "family": "js", + "toolchain": "Google Closure Compiler", + "backend": "V8", + "language": "JavaScript", + "optLevel": "ADVANCED", + "flags": [ + "--compilation_level ADVANCED_OPTIMIZATIONS" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_esbuild", + "name": "esbuild", + "desc": "Go-based Bundler/Minifier", + "color": "#ffcc00", + "compilation": { + "family": "js", + "toolchain": "esbuild", + "backend": "Go (native)", + "language": "JavaScript", + "optLevel": "minify", + "flags": [ + "--minify", + "--bundle" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_swc", + "name": "SWC", + "desc": "Rust-based JS Transpiler", + "color": "#ff6b35", + "compilation": { + "family": "js", + "toolchain": "SWC", + "backend": "Rust/LLVM", + "language": "JavaScript", + "optLevel": "minify", + "flags": [ + "--minify" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_tsc", + "name": "TypeScript (tsc)", + "desc": "Official TS Compiler", + "color": "#3178c6", + "compilation": { + "family": "js", + "toolchain": "tsc", + "backend": "V8", + "language": "TypeScript", + "optLevel": "ES2020", + "flags": [ + "--target ES2020", + "--strict" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_bigint", + "name": "JS BigInt", + "desc": "64-bit Integer Math", + "color": "#f7df1e", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_rust", + "name": "Rust (wasm-pack)", + "desc": "LLVM/Rust Toolchain", + "color": "#dea584", + "compilation": { + "family": "wasm", + "toolchain": "wasm-pack", + "backend": "LLVM", + "language": "Rust", + "optLevel": "O3", + "flags": [ + "--release" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_cheerp", + "name": "Cheerp (C++)", + "desc": "C++ Toolchain", + "color": "#d63031", + "compilation": { + "family": "wasm", + "toolchain": "Cheerp", + "backend": "Cheerp/LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-target cheerp-wasm" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_emcc", + "name": "Emscripten (C)", + "desc": "Pure C→WASM Baseline", + "color": "#a29bfe", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASM=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_javy", + "name": "Javy (JS→WASM)", + "desc": "JS via QuickJS in WASM", + "color": "#fd79a8", + "compilation": { + "family": "wasm", + "toolchain": "Javy", + "backend": "QuickJS + WASM", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_as", + "name": "AssemblyScript Suite", + "desc": "Base vs Optimized vs AOT", + "color": "#007acc", + "compilation": { + "family": "wasm", + "toolchain": "asc", + "backend": "Binaryen", + "language": "AssemblyScript", + "optLevel": "O3s", + "flags": [ + "-O3", + "--runtime minimal" + ], + "postProcess": [ + "wasm-opt -O3", + "WasmEdge AOT" + ], + "status": "real" + } + }, + { + "id": "wasm_simd", + "name": "WASM + SIMD", + "desc": "Vector Operations", + "color": "#2ecc71", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-msimd128", + "-s WASM=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_threads", + "name": "WASM + Threads", + "desc": "SharedArrayBuffer", + "color": "#e84393", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_openmp", + "name": "WASM + OpenMP", + "desc": "OMP Runtime + libomp", + "color": "#ff4757", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-fopenmp", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_max", + "name": "WASM Max", + "desc": "Threads + SIMD (No OMP)", + "color": "#ff0000", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-msimd128", + "-s USE_PTHREADS=1" + ], + "postProcess": [ + "wasm-opt -O3" + ], + "status": "real" + } + }, + { + "id": "wasm64", + "name": "WASM64", + "desc": "64-bit Memory Address Space", + "color": "#1abc9c", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASM=2", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasmfs", + "name": "WASMFS", + "desc": "In-Memory Filesystem for WASM", + "color": "#16a085", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASMFS=1", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "webgl_compute", + "name": "WebGL Compute", + "desc": "Fragment Shader Compute", + "color": "#00d4ff", + "compilation": { + "family": "gpu", + "toolchain": "GLSL→GPU driver", + "backend": "GPU (fragment shader)", + "language": "GLSL ES 3.0", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_compute", + "name": "WebGPU Compute", + "desc": "WGSL Compute Shaders", + "color": "#8e44ad", + "compilation": { + "family": "gpu", + "toolchain": "WGSL→GPU driver", + "backend": "GPU (compute shader)", + "language": "WGSL", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_dispatch", + "name": "WebGPU Dispatch Overhead", + "desc": "JS ↔ GPU Binding Stress", + "color": "#e67e22", + "compilation": { + "family": "gpu", + "toolchain": "WGSL→GPU driver", + "backend": "GPU (compute shader)", + "language": "WGSL", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_dispatch_wasm", + "name": "WebGPU Dispatch (WASM)", + "desc": "Real C++ via Emscripten + Dawn (experimental)", + "color": "#c0392b", + "compilation": { + "family": "wasm", + "toolchain": "emcc→Dawn glue", + "backend": "Emscripten/WebGPU", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s USE_WEBGPU=1" + ], + "postProcess": [], + "status": "experimental" + } + } +]; + +const multipliers = { + "js_inline": 1, + "js_external": 1.05, + "js_wasm_std": 2.5, + "js_terser": 1.05, + "js_closure": 1.4, + "js_esbuild": 1.08, + "js_swc": 1.07, + "js_tsc": 1.02, + "js_bigint": 0.8, + "wasm_rust": 2.5, + "wasm_cheerp": 2.45, + "wasm_emcc": 2.4, + "wasm_javy": 0.6, + "wasm_as": 2.3, + "wasm_simd": 3.5, + "wasm_threads": 4, + "wasm_openmp": 4.3, + "wasm_max": 4.5, + "wasm64": 2.3, + "wasmfs": 2, + "webgl_compute": 8, + "webgpu_compute": 12, + "webgpu_dispatch": 10, + "webgpu_dispatch_wasm": 2.5 +}; + +const wasmLoaderConfigs = [ + "wasm_rust", + "wasm_cheerp", + "wasm_as", + "wasm_openmp", + "wasm_max", + "wasm_simd", + "wasm_threads", + "wasm_emcc", + "wasm_javy", + "wasm64", + "wasmfs" +]; + +const machineProfiles = { + "reference": { + "id": "reference", + "name": "Reference Workstation", + "description": "Baseline capture machine — 8-core x86 CPU, integrated GPU, 16 GB RAM.", + "multiplier": 1, + "familyMultipliers": { + "js": 1, + "wasm": 1, + "gpu": 1 + }, + "nativeFamily": "js" + }, + "single_core_js": { + "id": "single_core_js", + "name": "Single-Core JS", + "description": "Low-power single-core CPU, no SIMD, no threads. JS runs best; WASM and GPU suffer heavy penalties.", + "multiplier": 0.55, + "familyMultipliers": { + "js": 0.9, + "wasm": 0.35, + "gpu": 0.02 + }, + "nativeFamily": "js" + }, + "multi_threaded": { + "id": "multi_threaded", + "name": "Multi-Threaded WASM", + "description": "16-core desktop with pthread & SIMD128 support. WASM threaded workloads thrive; GPU is secondary.", + "multiplier": 1.3, + "familyMultipliers": { + "js": 0.85, + "wasm": 1.9, + "gpu": 0.4 + }, + "nativeFamily": "wasm" + }, + "webgpu_high_end": { + "id": "webgpu_high_end", + "name": "WebGPU High-End", + "description": "Desktop with dedicated RTX-class GPU. Compute shaders dominate; CPU-bound work is comparatively slower.", + "multiplier": 1.6, + "familyMultipliers": { + "js": 0.6, + "wasm": 0.7, + "gpu": 3.2 + }, + "nativeFamily": "gpu" + }, + "low_power_mobile": { + "id": "low_power_mobile", + "name": "Low-Power Mobile", + "description": "ARM mobile chip (4-core, Mali GPU). Battery-optimized and thermally constrained across the board.", + "multiplier": 0.3, + "familyMultipliers": { + "js": 0.75, + "wasm": 0.5, + "gpu": 0.35 + }, + "nativeFamily": "js" + }, + "dedicated_gpu": { + "id": "dedicated_gpu", + "name": "Dedicated GPU Server", + "description": "Data-center node with A100/H100 class GPU. Massive parallel throughput for compute; CPU is a bottleneck.", + "multiplier": 2.2, + "familyMultipliers": { + "js": 0.4, + "wasm": 0.5, + "gpu": 5.5 + }, + "nativeFamily": "gpu" + } +}; + +module.exports = { configurations, multipliers, wasmLoaderConfigs, machineProfiles }; diff --git a/backend/benchmarks/configs.js b/backend/benchmarks/configs.js index ab3274d..daa1aa9 100644 --- a/backend/benchmarks/configs.js +++ b/backend/benchmarks/configs.js @@ -1,110 +1,10 @@ // backend/benchmarks/configs.js +// +// Config data (configurations, multipliers, machineProfiles) is generated from +// shared/benchmark-registry.json — see scripts/generate-benchmark-config.js. +// This file only holds the mock benchmark-running logic. -const configurations = [ - // --- A. Baseline Web --- - { - id: 'js_inline', name: 'Inline Script', desc: 'Standard JS (HTML)', color: '#f1e05a', - compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' }, - }, - { - id: 'js_external', name: 'External File', desc: 'Standard JS (.js)', color: '#f0db4f', - compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' }, - }, - { - id: 'js_wasm_std', name: 'JS + WASM', desc: 'Vanilla WASM Loading', color: '#654ff0', - compilation: { family: 'wasm', toolchain: 'WebAssembly.compile()', backend: 'Browser WASM engine', language: 'WebAssembly', optLevel: 'none', flags: [], postProcess: [], status: 'real' }, - }, - - // --- B. JS Optimizers --- - { - id: 'js_terser', name: 'JS + Terser', desc: 'Minified & Mangled', color: '#fab1a0', - compilation: { family: 'js', toolchain: 'Terser', backend: 'V8', language: 'JavaScript', optLevel: 'minify+mangle', flags: ['--compress', '--mangle'], postProcess: [], status: 'simulated' }, - }, - { - id: 'js_closure', name: 'Closure Compiler', desc: 'Advanced Optimization', color: '#e17055', - compilation: { family: 'js', toolchain: 'Google Closure Compiler', backend: 'V8', language: 'JavaScript', optLevel: 'ADVANCED', flags: ['--compilation_level ADVANCED_OPTIMIZATIONS'], postProcess: [], status: 'simulated' }, - }, - - // --- B2. Modern JS Bundler/Transpiler Tools --- - { - id: 'js_esbuild', name: 'esbuild', desc: 'Go-based Bundler/Minifier', color: '#ffcc00', - compilation: { family: 'js', toolchain: 'esbuild', backend: 'Go (native)', language: 'JavaScript', optLevel: 'minify', flags: ['--minify', '--bundle'], postProcess: [], status: 'simulated' }, - }, - { - id: 'js_swc', name: 'SWC', desc: 'Rust-based JS Transpiler', color: '#ff6b35', - compilation: { family: 'js', toolchain: 'SWC', backend: 'Rust/LLVM', language: 'JavaScript', optLevel: 'minify', flags: ['--minify'], postProcess: [], status: 'simulated' }, - }, - { - id: 'js_tsc', name: 'TypeScript (tsc)', desc: 'Official TS Compiler', color: '#3178c6', - compilation: { family: 'js', toolchain: 'tsc', backend: 'V8', language: 'TypeScript', optLevel: 'ES2020', flags: ['--target ES2020', '--strict'], postProcess: [], status: 'simulated' }, - }, - - // --- C. Data & Compilers --- - { - id: 'js_bigint', name: 'JS BigInt', desc: '64-bit Integer Math', color: '#f7df1e', - compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' }, - }, - { - id: 'wasm_rust', name: 'Rust (wasm-pack)', desc: 'LLVM/Rust Toolchain', color: '#dea584', - compilation: { family: 'wasm', toolchain: 'wasm-pack', backend: 'LLVM', language: 'Rust', optLevel: 'O3', flags: ['--release'], postProcess: [], status: 'real' }, - }, - { - id: 'wasm_cheerp', name: 'Cheerp (C++)', desc: 'C++ Toolchain', color: '#d63031', - compilation: { family: 'wasm', toolchain: 'Cheerp', backend: 'Cheerp/LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-target cheerp-wasm'], postProcess: [], status: 'simulated' }, - }, - { - id: 'wasm_emcc', name: 'Emscripten (C)', desc: 'Pure C→WASM Baseline', color: '#a29bfe', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C', optLevel: 'O3', flags: ['-O3', '-s WASM=1'], postProcess: [], status: 'simulated' }, - }, - { - id: 'wasm_javy', name: 'Javy (JS→WASM)', desc: 'JS via QuickJS in WASM', color: '#fd79a8', - compilation: { family: 'wasm', toolchain: 'Javy', backend: 'QuickJS + WASM', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' }, - }, - - // MERGED: AssemblyScript Suite - { - id: 'wasm_as', name: 'AssemblyScript Suite', desc: 'Base vs Optimized vs AOT', color: '#007acc', - compilation: { family: 'wasm', toolchain: 'asc', backend: 'Binaryen', language: 'AssemblyScript', optLevel: 'O3s', flags: ['-O3', '--runtime minimal'], postProcess: ['wasm-opt -O3', 'WasmEdge AOT'], status: 'real' }, - }, - - // --- E. Hardware Acceleration --- - { - id: 'wasm_simd', name: 'WASM + SIMD', desc: 'Vector Operations', color: '#2ecc71', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-msimd128', '-s WASM=1'], postProcess: [], status: 'real' }, - }, - { - id: 'wasm_threads', name: 'WASM + Threads', desc: 'SharedArrayBuffer', color: '#e84393', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s USE_PTHREADS=1', '-s WASM=1'], postProcess: [], status: 'real' }, - }, - { - id: 'wasm_openmp', name: 'WASM + OpenMP', desc: 'OMP Runtime + libomp', color: '#ff4757', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-fopenmp', '-s USE_PTHREADS=1'], postProcess: [], status: 'real' }, - }, - { - id: 'wasm_max', name: 'WASM Max', desc: 'Threads + SIMD (No OMP)', color: '#ff0000', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-msimd128', '-s USE_PTHREADS=1'], postProcess: ['wasm-opt -O3'], status: 'real' }, - }, - - // --- G. WASM64 & Filesystem --- - { - id: 'wasm64', name: 'WASM64', desc: '64-bit Memory Address Space', color: '#1abc9c', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s WASM=2', '-s USE_PTHREADS=1'], postProcess: [], status: 'simulated' }, - }, - { - id: 'wasmfs', name: 'WASMFS', desc: 'In-Memory Filesystem for WASM', color: '#16a085', - compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s WASMFS=1', '-s USE_PTHREADS=1'], postProcess: [], status: 'simulated' }, - }, - - // --- F. GPU Compute --- - { - id: 'webgl_compute', name: 'WebGL Compute', desc: 'Fragment Shader Compute', color: '#00d4ff', - compilation: { family: 'gpu', toolchain: 'GLSL→GPU driver', backend: 'GPU (fragment shader)', language: 'GLSL ES 3.0', optLevel: 'driver', flags: [], postProcess: [], status: 'real' }, - }, - { - id: 'webgpu_compute', name: 'WebGPU Compute', desc: 'WGSL Compute Shaders', color: '#8e44ad', - compilation: { family: 'gpu', toolchain: 'WGSL→GPU driver', backend: 'GPU (compute shader)', language: 'WGSL', optLevel: 'driver', flags: [], postProcess: [], status: 'real' }, - }, -]; +const { configurations, multipliers, machineProfiles } = require('./configs.generated'); const generateResult = (baseScore, variance, name) => ({ name, @@ -113,43 +13,14 @@ const generateResult = (baseScore, variance, name) => ({ }); function getMultiplier(configId) { - switch (configId) { - case 'js_inline': return 1.0; - case 'js_external': return 1.05; - case 'js_wasm_std': return 2.5; - case 'js_terser': return 1.05; - case 'js_closure': return 1.4; - case 'js_bigint': return 0.8; - // Modern JS bundlers (similar runtime to Terser, faster build time) - case 'js_esbuild': return 1.08; - case 'js_swc': return 1.07; - case 'js_tsc': return 1.02; - // Additional WASM toolchains - case 'wasm_emcc': return 2.4; - case 'wasm_javy': return 0.6; // JS-in-WASM overhead - case 'wasm_rust': return 2.5; - case 'wasm_cheerp': return 2.45; - case 'wasm_as': return 2.3; - case 'wasm_simd': return 3.5; - case 'wasm_threads': return 4.0; - case 'wasm_openmp': return 4.3; - case 'wasm_max': return 4.5; // Threads + SIMD can be slower than OpenMP due to scheduling overhead - case 'wasm64': return 2.3; // Same as vanilla WASM, memory addressing overhead minimal - case 'wasmfs': return 2.0; // Filesystem abstraction overhead - - // GPU: Realistic multipliers (10-20x for certain workloads, not all) - case 'webgl_compute': return 8.0; - case 'webgpu_compute': return 12.0; - - default: return 1.0; - } + return multipliers[configId] ?? 1.0; } async function runConfig(configId) { const m = getMultiplier(configId); const supportsWasmThreads = ['wasm_threads','wasm_simd','wasm_max','wasm64','wasmfs'].includes(configId); const supportsOpenMP = ['wasm_openmp', 'wasm_max'].includes(configId); - const isGPU = ['webgl_compute', 'webgpu_compute'].includes(configId); + const isGPU = ['webgl_compute', 'webgpu_compute', 'webgpu_dispatch'].includes(configId); // Load Score Simulation let loadScore = 150000; @@ -212,61 +83,4 @@ async function runConfigsSequential(configIds) { return result; } -/** - * Cross-machine hardware profiles for Phase 3 playback comparison. - * Each profile simulates how the same baseline workload would perform - * on a different class of hardware by applying a global multiplier - * and per-architecture family multipliers. - */ -const machineProfiles = { - reference: { - id: 'reference', - name: 'Reference Workstation', - description: 'Baseline capture machine — 8-core x86 CPU, integrated GPU, 16 GB RAM.', - multiplier: 1.0, - familyMultipliers: { js: 1.0, wasm: 1.0, gpu: 1.0 }, - nativeFamily: 'js', - }, - single_core_js: { - id: 'single_core_js', - name: 'Single-Core JS', - description: 'Low-power single-core CPU, no SIMD, no threads. JS runs best; WASM and GPU suffer heavy penalties.', - multiplier: 0.55, - familyMultipliers: { js: 0.9, wasm: 0.35, gpu: 0.02 }, - nativeFamily: 'js', - }, - multi_threaded: { - id: 'multi_threaded', - name: 'Multi-Threaded WASM', - description: '16-core desktop with pthread & SIMD128 support. WASM threaded workloads thrive; GPU is secondary.', - multiplier: 1.3, - familyMultipliers: { js: 0.85, wasm: 1.9, gpu: 0.4 }, - nativeFamily: 'wasm', - }, - webgpu_high_end: { - id: 'webgpu_high_end', - name: 'WebGPU High-End', - description: 'Desktop with dedicated RTX-class GPU. Compute shaders dominate; CPU-bound work is comparatively slower.', - multiplier: 1.6, - familyMultipliers: { js: 0.6, wasm: 0.7, gpu: 3.2 }, - nativeFamily: 'gpu', - }, - low_power_mobile: { - id: 'low_power_mobile', - name: 'Low-Power Mobile', - description: 'ARM mobile chip (4-core, Mali GPU). Battery-optimized and thermally constrained across the board.', - multiplier: 0.3, - familyMultipliers: { js: 0.75, wasm: 0.5, gpu: 0.35 }, - nativeFamily: 'js', - }, - dedicated_gpu: { - id: 'dedicated_gpu', - name: 'Dedicated GPU Server', - description: 'Data-center node with A100/H100 class GPU. Massive parallel throughput for compute; CPU is a bottleneck.', - multiplier: 2.2, - familyMultipliers: { js: 0.4, wasm: 0.5, gpu: 5.5 }, - nativeFamily: 'gpu', - }, -}; - module.exports = { configurations, runConfig, runConfigsSequential, machineProfiles }; diff --git a/package.json b/package.json index 3d20930..7bb03ce 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "build:all-wasm": "npm run build:physics && npm run build:omp && cd backend/benchmarks/rust && ./build.sh && echo 'Cheerp: Run backend/benchmarks/cheerp/build.sh manually'", "build:rust": "cd backend/benchmarks/rust && ./build.sh", "build:cheerp": "cd backend/benchmarks/cheerp && ./build.sh", + "config:generate": "node scripts/generate-benchmark-config.js", + "config:check": "node scripts/generate-benchmark-config.js --check", "test": "echo \"No tests yet\" && exit 0" }, "keywords": [ diff --git a/scripts/generate-benchmark-config.js b/scripts/generate-benchmark-config.js new file mode 100644 index 0000000..977820c --- /dev/null +++ b/scripts/generate-benchmark-config.js @@ -0,0 +1,102 @@ +#!/usr/bin/env node +// Generates backend/benchmarks/configs.generated.js and src/generated/benchmarkRegistry.js +// from the single hand-edited source: shared/benchmark-registry.json +// +// Usage: +// node scripts/generate-benchmark-config.js # write generated files +// node scripts/generate-benchmark-config.js --check # exit 1 if generated files are stale + +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.resolve(__dirname, '..'); +const REGISTRY_PATH = path.join(ROOT, 'shared', 'benchmark-registry.json'); +const BACKEND_OUT = path.join(ROOT, 'backend', 'benchmarks', 'configs.generated.js'); +const FRONTEND_OUT = path.join(ROOT, 'src', 'generated', 'benchmarkRegistry.js'); + +const HEADER = `// AUTO-GENERATED by scripts/generate-benchmark-config.js — DO NOT EDIT BY HAND. +// Source of truth: shared/benchmark-registry.json +// Run \`npm run config:generate\` after editing the registry to refresh this file. +`; + +function loadRegistry() { + const raw = fs.readFileSync(REGISTRY_PATH, 'utf8'); + return JSON.parse(raw); +} + +function buildMultipliers(configurations) { + const multipliers = {}; + for (const cfg of configurations) { + multipliers[cfg.id] = cfg.multiplier; + } + return multipliers; +} + +function renderBackend(registry) { + const { configurations, machineProfiles, wasmLoaderConfigs } = registry; + const multipliers = buildMultipliers(configurations); + const configsNoMultiplier = configurations.map(({ multiplier, ...rest }) => rest); + + return `${HEADER} +const configurations = ${JSON.stringify(configsNoMultiplier, null, 2)}; + +const multipliers = ${JSON.stringify(multipliers, null, 2)}; + +const wasmLoaderConfigs = ${JSON.stringify(wasmLoaderConfigs, null, 2)}; + +const machineProfiles = ${JSON.stringify(machineProfiles, null, 2)}; + +module.exports = { configurations, multipliers, wasmLoaderConfigs, machineProfiles }; +`; +} + +function renderFrontend(registry) { + const { configurations, machineProfiles, wasmLoaderConfigs } = registry; + const multipliers = buildMultipliers(configurations); + const configsNoMultiplier = configurations.map(({ multiplier, ...rest }) => rest); + + return `${HEADER} +export const configurations = ${JSON.stringify(configsNoMultiplier, null, 2)}; + +export const multipliers = ${JSON.stringify(multipliers, null, 2)}; + +export const wasmLoaderConfigs = ${JSON.stringify(wasmLoaderConfigs, null, 2)}; + +export const machineProfiles = ${JSON.stringify(machineProfiles, null, 2)}; +`; +} + +function main() { + const check = process.argv.includes('--check'); + const registry = loadRegistry(); + + const outputs = [ + [BACKEND_OUT, renderBackend(registry)], + [FRONTEND_OUT, renderFrontend(registry)], + ]; + + if (check) { + let stale = false; + for (const [outPath, content] of outputs) { + const existing = fs.existsSync(outPath) ? fs.readFileSync(outPath, 'utf8') : null; + if (existing !== content) { + console.error(`Stale or missing generated file: ${path.relative(ROOT, outPath)}`); + stale = true; + } + } + if (stale) { + console.error('\nRun `npm run config:generate` and commit the result.'); + process.exit(1); + } + console.log('Generated benchmark config files are up to date.'); + return; + } + + for (const [outPath, content] of outputs) { + fs.mkdirSync(path.dirname(outPath), { recursive: true }); + fs.writeFileSync(outPath, content); + console.log(`Wrote ${path.relative(ROOT, outPath)}`); + } +} + +main(); diff --git a/shared/benchmark-registry.json b/shared/benchmark-registry.json new file mode 100644 index 0000000..fe84e04 --- /dev/null +++ b/shared/benchmark-registry.json @@ -0,0 +1,142 @@ +{ + "$schema": "./benchmark-registry.schema.json", + "_comment": "Canonical benchmark configuration registry. This is the ONLY hand-edited config source file in the project. Run `npm run config:generate` after editing to regenerate backend/benchmarks/configs.generated.js and src/generated/benchmarkRegistry.js. Do not hand-edit those generated files.", + + "configurations": [ + { "id": "js_inline", "name": "Inline Script", "desc": "Standard JS (HTML)", "color": "#f1e05a", + "compilation": { "family": "js", "toolchain": "V8 JIT", "backend": "V8", "language": "JavaScript", "optLevel": "none", "flags": [], "postProcess": [], "status": "simulated" }, + "multiplier": 1.0 }, + { "id": "js_external", "name": "External File", "desc": "Standard JS (.js)", "color": "#f0db4f", + "compilation": { "family": "js", "toolchain": "V8 JIT", "backend": "V8", "language": "JavaScript", "optLevel": "none", "flags": [], "postProcess": [], "status": "simulated" }, + "multiplier": 1.05 }, + { "id": "js_wasm_std", "name": "JS + WASM", "desc": "Vanilla WASM Loading", "color": "#654ff0", + "compilation": { "family": "wasm", "toolchain": "WebAssembly.compile()", "backend": "Browser WASM engine", "language": "WebAssembly", "optLevel": "none", "flags": [], "postProcess": [], "status": "real" }, + "multiplier": 2.5 }, + + { "id": "js_terser", "name": "JS + Terser", "desc": "Minified & Mangled", "color": "#fab1a0", + "compilation": { "family": "js", "toolchain": "Terser", "backend": "V8", "language": "JavaScript", "optLevel": "minify+mangle", "flags": ["--compress", "--mangle"], "postProcess": [], "status": "simulated" }, + "multiplier": 1.05 }, + { "id": "js_closure", "name": "Closure Compiler", "desc": "Advanced Optimization", "color": "#e17055", + "compilation": { "family": "js", "toolchain": "Google Closure Compiler", "backend": "V8", "language": "JavaScript", "optLevel": "ADVANCED", "flags": ["--compilation_level ADVANCED_OPTIMIZATIONS"], "postProcess": [], "status": "simulated" }, + "multiplier": 1.4 }, + + { "id": "js_esbuild", "name": "esbuild", "desc": "Go-based Bundler/Minifier", "color": "#ffcc00", + "compilation": { "family": "js", "toolchain": "esbuild", "backend": "Go (native)", "language": "JavaScript", "optLevel": "minify", "flags": ["--minify", "--bundle"], "postProcess": [], "status": "simulated" }, + "multiplier": 1.08 }, + { "id": "js_swc", "name": "SWC", "desc": "Rust-based JS Transpiler", "color": "#ff6b35", + "compilation": { "family": "js", "toolchain": "SWC", "backend": "Rust/LLVM", "language": "JavaScript", "optLevel": "minify", "flags": ["--minify"], "postProcess": [], "status": "simulated" }, + "multiplier": 1.07 }, + { "id": "js_tsc", "name": "TypeScript (tsc)", "desc": "Official TS Compiler", "color": "#3178c6", + "compilation": { "family": "js", "toolchain": "tsc", "backend": "V8", "language": "TypeScript", "optLevel": "ES2020", "flags": ["--target ES2020", "--strict"], "postProcess": [], "status": "simulated" }, + "multiplier": 1.02 }, + + { "id": "js_bigint", "name": "JS BigInt", "desc": "64-bit Integer Math", "color": "#f7df1e", + "compilation": { "family": "js", "toolchain": "V8 JIT", "backend": "V8", "language": "JavaScript", "optLevel": "none", "flags": [], "postProcess": [], "status": "simulated" }, + "multiplier": 0.8 }, + { "id": "wasm_rust", "name": "Rust (wasm-pack)", "desc": "LLVM/Rust Toolchain", "color": "#dea584", + "compilation": { "family": "wasm", "toolchain": "wasm-pack", "backend": "LLVM", "language": "Rust", "optLevel": "O3", "flags": ["--release"], "postProcess": [], "status": "real" }, + "multiplier": 2.5 }, + { "id": "wasm_cheerp", "name": "Cheerp (C++)", "desc": "C++ Toolchain", "color": "#d63031", + "compilation": { "family": "wasm", "toolchain": "Cheerp", "backend": "Cheerp/LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-target cheerp-wasm"], "postProcess": [], "status": "simulated" }, + "multiplier": 2.45 }, + { "id": "wasm_emcc", "name": "Emscripten (C)", "desc": "Pure C→WASM Baseline", "color": "#a29bfe", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C", "optLevel": "O3", "flags": ["-O3", "-s WASM=1"], "postProcess": [], "status": "simulated" }, + "multiplier": 2.4 }, + { "id": "wasm_javy", "name": "Javy (JS→WASM)", "desc": "JS via QuickJS in WASM", "color": "#fd79a8", + "compilation": { "family": "wasm", "toolchain": "Javy", "backend": "QuickJS + WASM", "language": "JavaScript", "optLevel": "none", "flags": [], "postProcess": [], "status": "simulated" }, + "multiplier": 0.6 }, + + { "id": "wasm_as", "name": "AssemblyScript Suite", "desc": "Base vs Optimized vs AOT", "color": "#007acc", + "compilation": { "family": "wasm", "toolchain": "asc", "backend": "Binaryen", "language": "AssemblyScript", "optLevel": "O3s", "flags": ["-O3", "--runtime minimal"], "postProcess": ["wasm-opt -O3", "WasmEdge AOT"], "status": "real" }, + "multiplier": 2.3 }, + + { "id": "wasm_simd", "name": "WASM + SIMD", "desc": "Vector Operations", "color": "#2ecc71", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-msimd128", "-s WASM=1"], "postProcess": [], "status": "real" }, + "multiplier": 3.5 }, + { "id": "wasm_threads", "name": "WASM + Threads", "desc": "SharedArrayBuffer", "color": "#e84393", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-s USE_PTHREADS=1"], "postProcess": [], "status": "real" }, + "multiplier": 4.0 }, + { "id": "wasm_openmp", "name": "WASM + OpenMP", "desc": "OMP Runtime + libomp", "color": "#ff4757", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-fopenmp", "-s USE_PTHREADS=1"], "postProcess": [], "status": "real" }, + "multiplier": 4.3 }, + { "id": "wasm_max", "name": "WASM Max", "desc": "Threads + SIMD (No OMP)", "color": "#ff0000", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-msimd128", "-s USE_PTHREADS=1"], "postProcess": ["wasm-opt -O3"], "status": "real" }, + "multiplier": 4.5 }, + + { "id": "wasm64", "name": "WASM64", "desc": "64-bit Memory Address Space", "color": "#1abc9c", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-s WASM=2", "-s USE_PTHREADS=1"], "postProcess": [], "status": "simulated" }, + "multiplier": 2.3 }, + { "id": "wasmfs", "name": "WASMFS", "desc": "In-Memory Filesystem for WASM", "color": "#16a085", + "compilation": { "family": "wasm", "toolchain": "emcc", "backend": "LLVM", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-s WASMFS=1", "-s USE_PTHREADS=1"], "postProcess": [], "status": "simulated" }, + "multiplier": 2.0 }, + + { "id": "webgl_compute", "name": "WebGL Compute", "desc": "Fragment Shader Compute", "color": "#00d4ff", + "compilation": { "family": "gpu", "toolchain": "GLSL→GPU driver", "backend": "GPU (fragment shader)", "language": "GLSL ES 3.0", "optLevel": "driver", "flags": [], "postProcess": [], "status": "real" }, + "multiplier": 8.0 }, + { "id": "webgpu_compute", "name": "WebGPU Compute", "desc": "WGSL Compute Shaders", "color": "#8e44ad", + "compilation": { "family": "gpu", "toolchain": "WGSL→GPU driver", "backend": "GPU (compute shader)", "language": "WGSL", "optLevel": "driver", "flags": [], "postProcess": [], "status": "real" }, + "multiplier": 12.0 }, + { "id": "webgpu_dispatch", "name": "WebGPU Dispatch Overhead", "desc": "JS ↔ GPU Binding Stress", "color": "#e67e22", + "compilation": { "family": "gpu", "toolchain": "WGSL→GPU driver", "backend": "GPU (compute shader)", "language": "WGSL", "optLevel": "driver", "flags": [], "postProcess": [], "status": "real" }, + "multiplier": 10.0 }, + { "id": "webgpu_dispatch_wasm", "name": "WebGPU Dispatch (WASM)", "desc": "Real C++ via Emscripten + Dawn (experimental)", "color": "#c0392b", + "compilation": { "family": "wasm", "toolchain": "emcc→Dawn glue", "backend": "Emscripten/WebGPU", "language": "C++", "optLevel": "O3", "flags": ["-O3", "-s USE_WEBGPU=1"], "postProcess": [], "status": "experimental" }, + "multiplier": 2.5 } + ], + + "wasmLoaderConfigs": [ + "wasm_rust", "wasm_cheerp", "wasm_as", "wasm_openmp", "wasm_max", + "wasm_simd", "wasm_threads", "wasm_emcc", "wasm_javy", "wasm64", "wasmfs" + ], + + "machineProfiles": { + "reference": { + "id": "reference", + "name": "Reference Workstation", + "description": "Baseline capture machine — 8-core x86 CPU, integrated GPU, 16 GB RAM.", + "multiplier": 1.0, + "familyMultipliers": { "js": 1.0, "wasm": 1.0, "gpu": 1.0 }, + "nativeFamily": "js" + }, + "single_core_js": { + "id": "single_core_js", + "name": "Single-Core JS", + "description": "Low-power single-core CPU, no SIMD, no threads. JS runs best; WASM and GPU suffer heavy penalties.", + "multiplier": 0.55, + "familyMultipliers": { "js": 0.9, "wasm": 0.35, "gpu": 0.02 }, + "nativeFamily": "js" + }, + "multi_threaded": { + "id": "multi_threaded", + "name": "Multi-Threaded WASM", + "description": "16-core desktop with pthread & SIMD128 support. WASM threaded workloads thrive; GPU is secondary.", + "multiplier": 1.3, + "familyMultipliers": { "js": 0.85, "wasm": 1.9, "gpu": 0.4 }, + "nativeFamily": "wasm" + }, + "webgpu_high_end": { + "id": "webgpu_high_end", + "name": "WebGPU High-End", + "description": "Desktop with dedicated RTX-class GPU. Compute shaders dominate; CPU-bound work is comparatively slower.", + "multiplier": 1.6, + "familyMultipliers": { "js": 0.6, "wasm": 0.7, "gpu": 3.2 }, + "nativeFamily": "gpu" + }, + "low_power_mobile": { + "id": "low_power_mobile", + "name": "Low-Power Mobile", + "description": "ARM mobile chip (4-core, Mali GPU). Battery-optimized and thermally constrained across the board.", + "multiplier": 0.3, + "familyMultipliers": { "js": 0.75, "wasm": 0.5, "gpu": 0.35 }, + "nativeFamily": "js" + }, + "dedicated_gpu": { + "id": "dedicated_gpu", + "name": "Dedicated GPU Server", + "description": "Data-center node with A100/H100 class GPU. Massive parallel throughput for compute; CPU is a bottleneck.", + "multiplier": 2.2, + "familyMultipliers": { "js": 0.4, "wasm": 0.5, "gpu": 5.5 }, + "nativeFamily": "gpu" + } + } +} diff --git a/src/components/BenchmarkRunner.js b/src/components/BenchmarkRunner.js index 9cd7a54..35d8d94 100644 --- a/src/components/BenchmarkRunner.js +++ b/src/components/BenchmarkRunner.js @@ -2,50 +2,7 @@ import React, { useState, useEffect } from 'react'; import './BenchmarkRunner.css'; import { loadWasmModule } from '../utils/wasmLoader'; import { loadWebGPUWasmBench } from '../utils/webgpuWasmBenchLoader'; - -// 1. Define the Master List of "Machines" -// Keep in sync with backend/benchmarks/configs.js -const configurations = [ - // --- A. Baseline Web --- - { id: 'js_inline', name: 'Inline Script', desc: 'Standard JS (HTML)', color: '#f1e05a', compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' } }, - { id: 'js_external', name: 'External File', desc: 'Standard JS (.js)', color: '#f0db4f', compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' } }, - { id: 'js_wasm_std', name: 'JS + WASM', desc: 'Vanilla WASM Loading', color: '#654ff0', compilation: { family: 'wasm', toolchain: 'WebAssembly.compile()', backend: 'Browser WASM engine', language: 'WebAssembly', optLevel: 'none', flags: [], postProcess: [], status: 'real' } }, - - // --- B. JS Optimizers --- - { id: 'js_terser', name: 'JS + Terser', desc: 'Minified & Mangled', color: '#fab1a0', compilation: { family: 'js', toolchain: 'Terser', backend: 'V8', language: 'JavaScript', optLevel: 'minify+mangle', flags: ['--compress', '--mangle'], postProcess: [], status: 'simulated' } }, - { id: 'js_closure', name: 'Closure Compiler', desc: 'Advanced Optimization', color: '#e17055', compilation: { family: 'js', toolchain: 'Google Closure Compiler', backend: 'V8', language: 'JavaScript', optLevel: 'ADVANCED', flags: ['--compilation_level ADVANCED_OPTIMIZATIONS'], postProcess: [], status: 'simulated' } }, - - // --- B2. Modern JS Bundler/Transpiler Tools --- - { id: 'js_esbuild', name: 'esbuild', desc: 'Go-based Bundler/Minifier', color: '#ffcc00', compilation: { family: 'js', toolchain: 'esbuild', backend: 'Go (native)', language: 'JavaScript', optLevel: 'minify', flags: ['--minify', '--bundle'], postProcess: [], status: 'simulated' } }, - { id: 'js_swc', name: 'SWC', desc: 'Rust-based JS Transpiler', color: '#ff6b35', compilation: { family: 'js', toolchain: 'SWC', backend: 'Rust/LLVM', language: 'JavaScript', optLevel: 'minify', flags: ['--minify'], postProcess: [], status: 'simulated' } }, - { id: 'js_tsc', name: 'TypeScript (tsc)', desc: 'Official TS Compiler', color: '#3178c6', compilation: { family: 'js', toolchain: 'tsc', backend: 'V8', language: 'TypeScript', optLevel: 'ES2020', flags: ['--target ES2020', '--strict'], postProcess: [], status: 'simulated' } }, - - // --- C. Data & Compilers --- - { id: 'js_bigint', name: 'JS BigInt', desc: '64-bit Integer Math', color: '#f7df1e', compilation: { family: 'js', toolchain: 'V8 JIT', backend: 'V8', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' } }, - { id: 'wasm_rust', name: 'Rust (wasm-pack)', desc: 'LLVM/Rust Toolchain', color: '#dea584', compilation: { family: 'wasm', toolchain: 'wasm-pack', backend: 'LLVM', language: 'Rust', optLevel: 'O3', flags: ['--release'], postProcess: [], status: 'real' } }, - { id: 'wasm_cheerp', name: 'Cheerp (C++)', desc: 'C++ Toolchain', color: '#d63031', compilation: { family: 'wasm', toolchain: 'Cheerp', backend: 'Cheerp/LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-target cheerp-wasm'], postProcess: [], status: 'simulated' } }, - { id: 'wasm_emcc', name: 'Emscripten (C)', desc: 'Pure C→WASM Baseline', color: '#a29bfe', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C', optLevel: 'O3', flags: ['-O3', '-s WASM=1'], postProcess: [], status: 'simulated' } }, - { id: 'wasm_javy', name: 'Javy (JS→WASM)', desc: 'JS via QuickJS in WASM', color: '#fd79a8', compilation: { family: 'wasm', toolchain: 'Javy', backend: 'QuickJS + WASM', language: 'JavaScript', optLevel: 'none', flags: [], postProcess: [], status: 'simulated' } }, - - // MERGED: AssemblyScript Suite (Base, wasm-opt, WasmEdge AOT shown as sub-bars) - { id: 'wasm_as', name: 'AssemblyScript Suite', desc: 'Base vs Optimized vs AOT', color: '#007acc', compilation: { family: 'wasm', toolchain: 'asc', backend: 'Binaryen', language: 'AssemblyScript', optLevel: 'O3s', flags: ['-O3', '--runtime minimal'], postProcess: ['wasm-opt -O3', 'WasmEdge AOT'], status: 'real' } }, - - // --- E. Hardware Acceleration --- - { id: 'wasm_simd', name: 'WASM + SIMD', desc: 'Vector Operations', color: '#2ecc71', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-msimd128', '-s WASM=1'], postProcess: [], status: 'real' } }, - { id: 'wasm_threads', name: 'WASM + Threads', desc: 'SharedArrayBuffer', color: '#e84393', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s USE_PTHREADS=1'], postProcess: [], status: 'real' } }, - { id: 'wasm_openmp', name: 'WASM + OpenMP', desc: 'OMP Runtime + libomp', color: '#ff4757', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-fopenmp', '-s USE_PTHREADS=1'], postProcess: [], status: 'real' } }, - { id: 'wasm_max', name: 'WASM Max', desc: 'Threads + SIMD (No OMP)', color: '#ff0000', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-msimd128', '-s USE_PTHREADS=1'], postProcess: ['wasm-opt -O3'], status: 'real' } }, - - // --- G. WASM64 & Filesystem --- - { id: 'wasm64', name: 'WASM64', desc: '64-bit Memory Address Space', color: '#1abc9c', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s WASM=2', '-s USE_PTHREADS=1'], postProcess: [], status: 'simulated' } }, - { id: 'wasmfs', name: 'WASMFS', desc: 'In-Memory Filesystem', color: '#16a085', compilation: { family: 'wasm', toolchain: 'emcc', backend: 'LLVM', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s WASMFS=1', '-s USE_PTHREADS=1'], postProcess: [], status: 'simulated' } }, - - // --- F. GPU Compute --- - { id: 'webgl_compute', name: 'WebGL Compute', desc: 'Fragment Shader Compute', color: '#00d4ff', compilation: { family: 'gpu', toolchain: 'GLSL→GPU driver', backend: 'GPU (fragment shader)',language: 'GLSL ES 3.0', optLevel: 'driver', flags: [], postProcess: [], status: 'real' } }, - { id: 'webgpu_compute', name: 'WebGPU Compute', desc: 'WGSL Compute Shaders', color: '#8e44ad', compilation: { family: 'gpu', toolchain: 'WGSL→GPU driver', backend: 'GPU (compute shader)', language: 'WGSL', optLevel: 'driver', flags: [], postProcess: [], status: 'real' } }, - { id: 'webgpu_dispatch', name: 'WebGPU Dispatch Overhead', desc: 'JS ↔ GPU Binding Stress', color: '#e67e22', compilation: { family: 'gpu', toolchain: 'WGSL→GPU driver', backend: 'GPU (compute shader)', language: 'WGSL', optLevel: 'driver', flags: [], postProcess: [], status: 'real' } }, - { id: 'webgpu_dispatch_wasm', name: 'WebGPU Dispatch (WASM)', desc: 'Real C++ via Emscripten + Dawn (experimental)', color: '#c0392b', compilation: { family: 'wasm', toolchain: 'emcc→Dawn glue', backend: 'Emscripten/WebGPU', language: 'C++', optLevel: 'O3', flags: ['-O3', '-s USE_WEBGPU=1'], postProcess: [], status: 'experimental' } }, -]; +import { configurations, multipliers, wasmLoaderConfigs } from '../generated/benchmarkRegistry'; const calculateScore = (config) => { if (!config.tests || config.tests.length === 0) return 0; @@ -58,8 +15,8 @@ const generateResult = (baseScore, variance, name) => ({ stats: { mean: 0.00001, deviation: 0.000001, margin: 2.0 } }); -// Define WASM-supported configs (attempt real WASM load before falling back to simulation) -const wasmConfigs = ['wasm_rust', 'wasm_cheerp', 'wasm_as', 'wasm_openmp', 'wasm_max', 'wasm_simd', 'wasm_threads', 'wasm_emcc', 'wasm_javy', 'wasm64', 'wasmfs']; +// WASM-supported configs (attempt real WASM load before falling back to simulation) +const wasmConfigs = wasmLoaderConfigs; const simulateWebGPUWasmDispatch = () => new Promise((resolve) => { setTimeout(() => { @@ -348,37 +305,9 @@ const mockRunConfig = async (configId) => { // 4. FALLBACK SIMULATION return new Promise((resolve) => { - let m = 1.0; - let startupDelay = 0; - - switch (configId) { - case 'js_inline': m = 1.0; break; - case 'js_external': m = 1.05; break; - case 'js_wasm_std': m = 2.5; break; - case 'js_terser': m = 1.05; break; - case 'js_closure': m = 1.4; break; - case 'js_bigint': m = 0.8; break; - case 'js_esbuild': m = 1.08; break; - case 'js_swc': m = 1.07; break; - case 'js_tsc': m = 1.02; break; - case 'wasm_emcc': m = 2.4; break; - case 'wasm_javy': m = 0.6; break; - case 'wasm_rust': m = 2.5; break; - case 'wasm_cheerp': m = 2.45; break; - case 'wasm_as': m = 2.3; break; // Base AssemblyScript - case 'wasm_simd': m = 3.5; break; - case 'wasm_threads': m = 4.0; break; - case 'wasm_openmp': m = 4.3; break; - case 'wasm_max': m = 4.5; break; - case 'wasm64': m = 2.3; break; - case 'wasmfs': m = 2.0; break; - case 'webgl_compute': m = 8.0; break; - case 'webgpu_compute': m = 12.0; break; - case 'webgpu_dispatch': m = 10.0; break; - case 'webgpu_dispatch_wasm': m = 2.5; break; - default: m = 1.0; - } - + const m = multipliers[configId] ?? 1.0; + + setTimeout(() => { let results = []; diff --git a/src/generated/benchmarkRegistry.js b/src/generated/benchmarkRegistry.js new file mode 100644 index 0000000..6149dbb --- /dev/null +++ b/src/generated/benchmarkRegistry.js @@ -0,0 +1,561 @@ +// AUTO-GENERATED by scripts/generate-benchmark-config.js — DO NOT EDIT BY HAND. +// Source of truth: shared/benchmark-registry.json +// Run `npm run config:generate` after editing the registry to refresh this file. + +export const configurations = [ + { + "id": "js_inline", + "name": "Inline Script", + "desc": "Standard JS (HTML)", + "color": "#f1e05a", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_external", + "name": "External File", + "desc": "Standard JS (.js)", + "color": "#f0db4f", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_wasm_std", + "name": "JS + WASM", + "desc": "Vanilla WASM Loading", + "color": "#654ff0", + "compilation": { + "family": "wasm", + "toolchain": "WebAssembly.compile()", + "backend": "Browser WASM engine", + "language": "WebAssembly", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "js_terser", + "name": "JS + Terser", + "desc": "Minified & Mangled", + "color": "#fab1a0", + "compilation": { + "family": "js", + "toolchain": "Terser", + "backend": "V8", + "language": "JavaScript", + "optLevel": "minify+mangle", + "flags": [ + "--compress", + "--mangle" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_closure", + "name": "Closure Compiler", + "desc": "Advanced Optimization", + "color": "#e17055", + "compilation": { + "family": "js", + "toolchain": "Google Closure Compiler", + "backend": "V8", + "language": "JavaScript", + "optLevel": "ADVANCED", + "flags": [ + "--compilation_level ADVANCED_OPTIMIZATIONS" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_esbuild", + "name": "esbuild", + "desc": "Go-based Bundler/Minifier", + "color": "#ffcc00", + "compilation": { + "family": "js", + "toolchain": "esbuild", + "backend": "Go (native)", + "language": "JavaScript", + "optLevel": "minify", + "flags": [ + "--minify", + "--bundle" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_swc", + "name": "SWC", + "desc": "Rust-based JS Transpiler", + "color": "#ff6b35", + "compilation": { + "family": "js", + "toolchain": "SWC", + "backend": "Rust/LLVM", + "language": "JavaScript", + "optLevel": "minify", + "flags": [ + "--minify" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_tsc", + "name": "TypeScript (tsc)", + "desc": "Official TS Compiler", + "color": "#3178c6", + "compilation": { + "family": "js", + "toolchain": "tsc", + "backend": "V8", + "language": "TypeScript", + "optLevel": "ES2020", + "flags": [ + "--target ES2020", + "--strict" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "js_bigint", + "name": "JS BigInt", + "desc": "64-bit Integer Math", + "color": "#f7df1e", + "compilation": { + "family": "js", + "toolchain": "V8 JIT", + "backend": "V8", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_rust", + "name": "Rust (wasm-pack)", + "desc": "LLVM/Rust Toolchain", + "color": "#dea584", + "compilation": { + "family": "wasm", + "toolchain": "wasm-pack", + "backend": "LLVM", + "language": "Rust", + "optLevel": "O3", + "flags": [ + "--release" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_cheerp", + "name": "Cheerp (C++)", + "desc": "C++ Toolchain", + "color": "#d63031", + "compilation": { + "family": "wasm", + "toolchain": "Cheerp", + "backend": "Cheerp/LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-target cheerp-wasm" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_emcc", + "name": "Emscripten (C)", + "desc": "Pure C→WASM Baseline", + "color": "#a29bfe", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASM=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_javy", + "name": "Javy (JS→WASM)", + "desc": "JS via QuickJS in WASM", + "color": "#fd79a8", + "compilation": { + "family": "wasm", + "toolchain": "Javy", + "backend": "QuickJS + WASM", + "language": "JavaScript", + "optLevel": "none", + "flags": [], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasm_as", + "name": "AssemblyScript Suite", + "desc": "Base vs Optimized vs AOT", + "color": "#007acc", + "compilation": { + "family": "wasm", + "toolchain": "asc", + "backend": "Binaryen", + "language": "AssemblyScript", + "optLevel": "O3s", + "flags": [ + "-O3", + "--runtime minimal" + ], + "postProcess": [ + "wasm-opt -O3", + "WasmEdge AOT" + ], + "status": "real" + } + }, + { + "id": "wasm_simd", + "name": "WASM + SIMD", + "desc": "Vector Operations", + "color": "#2ecc71", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-msimd128", + "-s WASM=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_threads", + "name": "WASM + Threads", + "desc": "SharedArrayBuffer", + "color": "#e84393", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_openmp", + "name": "WASM + OpenMP", + "desc": "OMP Runtime + libomp", + "color": "#ff4757", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-fopenmp", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "real" + } + }, + { + "id": "wasm_max", + "name": "WASM Max", + "desc": "Threads + SIMD (No OMP)", + "color": "#ff0000", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-msimd128", + "-s USE_PTHREADS=1" + ], + "postProcess": [ + "wasm-opt -O3" + ], + "status": "real" + } + }, + { + "id": "wasm64", + "name": "WASM64", + "desc": "64-bit Memory Address Space", + "color": "#1abc9c", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASM=2", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "wasmfs", + "name": "WASMFS", + "desc": "In-Memory Filesystem for WASM", + "color": "#16a085", + "compilation": { + "family": "wasm", + "toolchain": "emcc", + "backend": "LLVM", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s WASMFS=1", + "-s USE_PTHREADS=1" + ], + "postProcess": [], + "status": "simulated" + } + }, + { + "id": "webgl_compute", + "name": "WebGL Compute", + "desc": "Fragment Shader Compute", + "color": "#00d4ff", + "compilation": { + "family": "gpu", + "toolchain": "GLSL→GPU driver", + "backend": "GPU (fragment shader)", + "language": "GLSL ES 3.0", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_compute", + "name": "WebGPU Compute", + "desc": "WGSL Compute Shaders", + "color": "#8e44ad", + "compilation": { + "family": "gpu", + "toolchain": "WGSL→GPU driver", + "backend": "GPU (compute shader)", + "language": "WGSL", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_dispatch", + "name": "WebGPU Dispatch Overhead", + "desc": "JS ↔ GPU Binding Stress", + "color": "#e67e22", + "compilation": { + "family": "gpu", + "toolchain": "WGSL→GPU driver", + "backend": "GPU (compute shader)", + "language": "WGSL", + "optLevel": "driver", + "flags": [], + "postProcess": [], + "status": "real" + } + }, + { + "id": "webgpu_dispatch_wasm", + "name": "WebGPU Dispatch (WASM)", + "desc": "Real C++ via Emscripten + Dawn (experimental)", + "color": "#c0392b", + "compilation": { + "family": "wasm", + "toolchain": "emcc→Dawn glue", + "backend": "Emscripten/WebGPU", + "language": "C++", + "optLevel": "O3", + "flags": [ + "-O3", + "-s USE_WEBGPU=1" + ], + "postProcess": [], + "status": "experimental" + } + } +]; + +export const multipliers = { + "js_inline": 1, + "js_external": 1.05, + "js_wasm_std": 2.5, + "js_terser": 1.05, + "js_closure": 1.4, + "js_esbuild": 1.08, + "js_swc": 1.07, + "js_tsc": 1.02, + "js_bigint": 0.8, + "wasm_rust": 2.5, + "wasm_cheerp": 2.45, + "wasm_emcc": 2.4, + "wasm_javy": 0.6, + "wasm_as": 2.3, + "wasm_simd": 3.5, + "wasm_threads": 4, + "wasm_openmp": 4.3, + "wasm_max": 4.5, + "wasm64": 2.3, + "wasmfs": 2, + "webgl_compute": 8, + "webgpu_compute": 12, + "webgpu_dispatch": 10, + "webgpu_dispatch_wasm": 2.5 +}; + +export const wasmLoaderConfigs = [ + "wasm_rust", + "wasm_cheerp", + "wasm_as", + "wasm_openmp", + "wasm_max", + "wasm_simd", + "wasm_threads", + "wasm_emcc", + "wasm_javy", + "wasm64", + "wasmfs" +]; + +export const machineProfiles = { + "reference": { + "id": "reference", + "name": "Reference Workstation", + "description": "Baseline capture machine — 8-core x86 CPU, integrated GPU, 16 GB RAM.", + "multiplier": 1, + "familyMultipliers": { + "js": 1, + "wasm": 1, + "gpu": 1 + }, + "nativeFamily": "js" + }, + "single_core_js": { + "id": "single_core_js", + "name": "Single-Core JS", + "description": "Low-power single-core CPU, no SIMD, no threads. JS runs best; WASM and GPU suffer heavy penalties.", + "multiplier": 0.55, + "familyMultipliers": { + "js": 0.9, + "wasm": 0.35, + "gpu": 0.02 + }, + "nativeFamily": "js" + }, + "multi_threaded": { + "id": "multi_threaded", + "name": "Multi-Threaded WASM", + "description": "16-core desktop with pthread & SIMD128 support. WASM threaded workloads thrive; GPU is secondary.", + "multiplier": 1.3, + "familyMultipliers": { + "js": 0.85, + "wasm": 1.9, + "gpu": 0.4 + }, + "nativeFamily": "wasm" + }, + "webgpu_high_end": { + "id": "webgpu_high_end", + "name": "WebGPU High-End", + "description": "Desktop with dedicated RTX-class GPU. Compute shaders dominate; CPU-bound work is comparatively slower.", + "multiplier": 1.6, + "familyMultipliers": { + "js": 0.6, + "wasm": 0.7, + "gpu": 3.2 + }, + "nativeFamily": "gpu" + }, + "low_power_mobile": { + "id": "low_power_mobile", + "name": "Low-Power Mobile", + "description": "ARM mobile chip (4-core, Mali GPU). Battery-optimized and thermally constrained across the board.", + "multiplier": 0.3, + "familyMultipliers": { + "js": 0.75, + "wasm": 0.5, + "gpu": 0.35 + }, + "nativeFamily": "js" + }, + "dedicated_gpu": { + "id": "dedicated_gpu", + "name": "Dedicated GPU Server", + "description": "Data-center node with A100/H100 class GPU. Massive parallel throughput for compute; CPU is a bottleneck.", + "multiplier": 2.2, + "familyMultipliers": { + "js": 0.4, + "wasm": 0.5, + "gpu": 5.5 + }, + "nativeFamily": "gpu" + } +}; diff --git a/src/utils/machineProfiles.js b/src/utils/machineProfiles.js index 990e2a8..ba4ae8f 100644 --- a/src/utils/machineProfiles.js +++ b/src/utils/machineProfiles.js @@ -1,59 +1,12 @@ /** * Cross-machine hardware profiles for frontend playback comparison. - * Mirrors backend/benchmarks/configs.js so the UI can simulate - * how baseline results would perform on different hardware classes. + * Data is generated from shared/benchmark-registry.json (single source of + * truth shared with the backend) — see scripts/generate-benchmark-config.js. */ -export const machineProfiles = { - reference: { - id: 'reference', - name: 'Reference Workstation', - description: 'Baseline capture machine — 8-core x86 CPU, integrated GPU, 16 GB RAM.', - multiplier: 1.0, - familyMultipliers: { js: 1.0, wasm: 1.0, gpu: 1.0 }, - nativeFamily: 'js', - }, - single_core_js: { - id: 'single_core_js', - name: 'Single-Core JS', - description: 'Low-power single-core CPU, no SIMD, no threads. JS runs best; WASM and GPU suffer heavy penalties.', - multiplier: 0.55, - familyMultipliers: { js: 0.9, wasm: 0.35, gpu: 0.02 }, - nativeFamily: 'js', - }, - multi_threaded: { - id: 'multi_threaded', - name: 'Multi-Threaded WASM', - description: '16-core desktop with pthread & SIMD128 support. WASM threaded workloads thrive; GPU is secondary.', - multiplier: 1.3, - familyMultipliers: { js: 0.85, wasm: 1.9, gpu: 0.4 }, - nativeFamily: 'wasm', - }, - webgpu_high_end: { - id: 'webgpu_high_end', - name: 'WebGPU High-End', - description: 'Desktop with dedicated RTX-class GPU. Compute shaders dominate; CPU-bound work is comparatively slower.', - multiplier: 1.6, - familyMultipliers: { js: 0.6, wasm: 0.7, gpu: 3.2 }, - nativeFamily: 'gpu', - }, - low_power_mobile: { - id: 'low_power_mobile', - name: 'Low-Power Mobile', - description: 'ARM mobile chip (4-core, Mali GPU). Battery-optimized and thermally constrained across the board.', - multiplier: 0.3, - familyMultipliers: { js: 0.75, wasm: 0.5, gpu: 0.35 }, - nativeFamily: 'js', - }, - dedicated_gpu: { - id: 'dedicated_gpu', - name: 'Dedicated GPU Server', - description: 'Data-center node with A100/H100 class GPU. Massive parallel throughput for compute; CPU is a bottleneck.', - multiplier: 2.2, - familyMultipliers: { js: 0.4, wasm: 0.5, gpu: 5.5 }, - nativeFamily: 'gpu', - }, -}; +import { machineProfiles } from '../generated/benchmarkRegistry'; + +export { machineProfiles }; /** Ordered list for dropdowns / selectors. */ export const machineProfileList = Object.values(machineProfiles);