webgpu-bench / index.html
GitHub Actions
sync from abhijitramesh/webgpu-bench@aac06bd55b
df975ba
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<script>(function(){var s=localStorage.getItem('theme');if(!s){s=(window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light';}document.documentElement.setAttribute('data-theme',s);})();</script>
<title>WebGPU Bench</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="/" class="header-brand">
<svg class="header-logo" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><line x1="9" y1="1" x2="9" y2="4"/><line x1="15" y1="1" x2="15" y2="4"/><line x1="9" y1="20" x2="9" y2="23"/><line x1="15" y1="20" x2="15" y2="23"/><line x1="20" y1="9" x2="23" y2="9"/><line x1="20" y1="14" x2="23" y2="14"/><line x1="1" y1="9" x2="4" y2="9"/><line x1="1" y1="14" x2="4" y2="14"/></svg>
<span class="header-title">WebGPU Bench</span>
</a>
<nav class="header-nav" aria-label="Primary">
<a href="run.html" class="header-link">Run</a>
<a href="methodology.html" class="header-link">Methodology</a>
<button id="theme-toggle" class="header-link theme-toggle-btn" type="button" title="Toggle theme" aria-label="Toggle dark mode">
<svg class="icon-sun" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<svg class="icon-moon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<a href="https://github.com/abhijitramesh/webgpu-bench" target="_blank" rel="noopener" class="header-link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.44 9.8 8.2 11.39.6.11.82-.26.82-.58v-2.03c-3.34.73-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.09-.74.08-.73.08-.73 1.2.09 1.84 1.24 1.84 1.24 1.07 1.83 2.81 1.3 3.5 1 .11-.78.42-1.3.76-1.6-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.13-.3-.54-1.52.12-3.18 0 0 1.01-.32 3.3 1.23a11.5 11.5 0 0 1 6.02 0c2.28-1.55 3.29-1.23 3.29-1.23.66 1.66.25 2.88.12 3.18.77.84 1.24 1.91 1.24 3.22 0 4.61-2.81 5.63-5.48 5.92.43.37.81 1.1.81 2.22v3.29c0 .32.22.7.82.58C20.57 21.8 24 17.3 24 12c0-6.63-5.37-12-12-12z"/></svg>
GitHub
</a>
</nav>
</div>
</header>
<main>
<div id="loading" aria-busy="true" aria-label="Loading benchmark data">
<div class="skeleton skeleton-hero" aria-hidden="true"></div>
<div class="skeleton skeleton-filters" aria-hidden="true"></div>
<div class="skeleton-stats" aria-hidden="true">
<div class="skeleton"></div>
<div class="skeleton"></div>
<div class="skeleton"></div>
</div>
<div class="skeleton skeleton-table" aria-hidden="true"></div>
</div>
<div id="dashboard" style="display: none;">
<!-- Hero -->
<section class="hero">
<div class="container hero-inner">
<div class="hero-copy">
<span class="hero-eyebrow" id="hero-live" hidden>
<span class="hero-eyebrow-dot" aria-hidden="true"></span>
<span id="hero-live-text">Live</span>
</span>
<h1 class="hero-title">WebGPU Bench</h1>
<p class="hero-lede">Real-browser benchmarks for <code>llama.cpp</code>'s WebGPU backend. GGUF models loaded via WebAssembly, measured across Chrome and Safari.</p>
<p class="hero-meta" id="hero-meta" hidden></p>
<div class="hero-actions">
<a href="run.html" class="btn btn-primary">Run on your machine</a>
<a href="methodology.html" class="btn btn-secondary">Methodology</a>
</div>
</div>
<aside class="hero-stat" id="hero-stat" aria-live="polite" hidden>
<span class="hero-stat-label">Top decode</span>
<span class="hero-stat-value">
<span class="hero-stat-num" id="hero-top-decode" data-target="0">0.0</span>
<span class="hero-stat-unit">tok/s</span>
</span>
<span class="hero-stat-meta" id="hero-top-meta"></span>
</aside>
</div>
</section>
<!-- Sticky head: filter bar + section jump links -->
<div class="sticky-head">
<!-- Filter Bar -->
<div class="filter-bar">
<div class="filter-bar-inner">
<div class="filter-group">
<label class="filter-label" for="filter-machine">Machine</label>
<select id="filter-machine" class="filter-select"></select>
</div>
<div class="filter-group">
<label class="filter-label" for="filter-browser">Browser</label>
<select id="filter-browser" class="filter-select"></select>
</div>
<div class="filter-group">
<label class="filter-label" for="filter-model">Model</label>
<select id="filter-model" class="filter-select"></select>
</div>
<div class="filter-group">
<label class="filter-label" for="filter-backend">Backend</label>
<select id="filter-backend" class="filter-select"></select>
</div>
<div class="filter-group">
<label class="filter-label" for="filter-status">Status</label>
<select id="filter-status" class="filter-select"></select>
</div>
<div class="filter-group">
<label class="filter-label">Quantization</label>
<div class="quant-dropdown" id="quant-dropdown">
<button class="quant-dropdown-btn" id="quant-dropdown-btn" type="button">
<span id="quant-dropdown-text">All Quants</span>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<div class="quant-dropdown-list" id="quant-options"></div>
</div>
</div>
<div class="filter-actions">
<button class="filter-reset-btn" id="filter-reset" type="button" disabled title="Reset all filters">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
<span class="filter-reset-label">Reset</span>
</button>
</div>
</div>
</div>
<!-- Section Navigation -->
<nav class="section-nav" id="section-nav" aria-label="Dashboard sections">
<div class="section-nav-track">
<button class="section-nav-item active" data-section="overview">Overview</button>
<button class="section-nav-item" data-section="results-section">Results</button>
<button class="section-nav-item" data-section="performance-section">Performance</button>
<button class="section-nav-item" data-section="errors-section">Errors</button>
<button class="section-nav-item" data-section="machines-section">Machines</button>
</div>
</nav>
</div><!-- /sticky-head -->
<!-- Overview -->
<section id="overview" class="dash-section">
<div class="container">
<div class="summary-grid">
<div class="stat-card">
<div class="stat-card-icon stat-card-icon--machines">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg>
</div>
<div class="stat-card-content">
<span class="stat-card-label">Machines</span>
<span class="stat-card-value" id="stat-machines" data-target="0">0</span>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon stat-card-icon--benchmarks">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<div class="stat-card-content">
<span class="stat-card-label">Benchmarks</span>
<span class="stat-card-value" id="stat-benchmarks" data-target="0">0</span>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon stat-card-icon--pass">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
</div>
<div class="stat-card-content">
<span class="stat-card-label">Pass Rate</span>
<span class="stat-card-value"><span id="stat-pass-rate" data-target="0">0</span><span class="stat-card-unit">%</span></span>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon stat-card-icon--decode">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 17 9 11 13 15 21 7"/><polyline points="14 7 21 7 21 14"/></svg>
</div>
<div class="stat-card-content">
<span class="stat-card-label">Best Decode</span>
<span class="stat-card-value"><span id="stat-best-decode" data-target="0">0.0</span><span class="stat-card-unit">tok/s</span></span>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon stat-card-icon--size">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
</div>
<div class="stat-card-content">
<span class="stat-card-label">Largest Run</span>
<span class="stat-card-value"><span id="stat-largest" data-target="0">0</span><span class="stat-card-unit">MB</span></span>
</div>
</div>
</div>
</div>
</section>
<!-- Results -->
<section id="results-section" class="dash-section">
<div class="container">
<div class="section-header">
<h2>Results</h2>
<span class="results-count" id="results-count"></span>
</div>
<div class="table-card">
<div class="results-wrapper" id="results-table" tabindex="0" role="region" aria-label="Benchmark results table"></div>
</div>
</div>
</section>
<!-- Performance Charts -->
<section id="performance-section" class="dash-section">
<div class="container">
<div class="section-header">
<h2>Performance</h2>
</div>
<div class="charts-grid">
<div class="chart-box"><canvas id="chart-decode"></canvas></div>
<div class="chart-box"><canvas id="chart-prefill"></canvas></div>
<div class="chart-box"><canvas id="chart-size"></canvas></div>
<div class="chart-box" id="machine-chart-section"><canvas id="chart-machine"></canvas></div>
</div>
<div class="section-header" style="margin-top: 32px;">
<h3 class="subsection-title">CPU vs WebGPU</h3>
<div class="metric-selector">
<label class="metric-selector-label" for="cpu-gpu-metric">Metric</label>
<select id="cpu-gpu-metric" class="filter-select" aria-label="CPU vs WebGPU metric">
<option value="decode_tok_s">Decode tok/s</option>
<option value="prefill_tok_s">Prefill tok/s</option>
</select>
</div>
</div>
<div class="charts-grid">
<div class="chart-box"><canvas id="chart-cpu-gpu"></canvas></div>
<div class="chart-box"><canvas id="chart-speedup"></canvas></div>
</div>
<div id="cpu-gpu-table" style="margin-top: 16px;"></div>
</div>
</section>
<!-- Error Analysis -->
<section id="errors-section" class="dash-section">
<div class="container">
<div class="section-header">
<h2>Error Analysis</h2>
</div>
<div id="error-table"></div>
</div>
</section>
<!-- Machines -->
<section id="machines-section" class="dash-section">
<div class="container">
<div class="section-header">
<h2>Machines</h2>
</div>
<div id="machine-info"></div>
</div>
</section>
</div>
</main>
<script type="module" src="js/app.js"></script>
</body>
</html>