Characterizing WebGPU Dispatch Overhead for LLM Inference Across Four GPU Vendors, Three Backends, and Three Browsers
Organizations: Independent Researcher
Abstract
WebGPU's security-focused design imposes per-operation validation that compounds across the many small dispatches in neural network inference, yet the true cost of this overhead is poorly characterized. We present a systematic characterization of WebGPU dispatch overhead for LLM inference at batch size 1, spanning four GPU vendors (NVIDIA, AMD, Apple, Intel), two native implementations (Dawn, wgpu-native) and three browsers (Chrome, Safari, Firefox), and two model sizes (Qwen2.5-0.5B and 1.5B). Our primary contribution is a sequential-dispatch methodology that reveals naive single-operation benchmarks overestimate dispatch cost by . The true per-dispatch cost of WebGPU API overhead alone is 24-36 s on Vulkan and 32-71 s on Metal, while the total per-operation overhead including Python cost is ~s, which turns out to be a distinction critical for optimization. On Vulkan, kernel fusion improves throughput by 53%, while CUDA fusion provides no benefit, confirming that per-operation overhead is a primary differentiator. LLM inference was tested across three major operating systems (Linux, Windows, macOS). We built , a PrivateUse1-based out-of-tree PyTorch backend and an FX-to-WebGPU compiler, which on our reference platform achieves 11--12% of CUDA performance. At dtype-matched float32, RTX PRO 2000 achieves 1.4 WebGPU's throughput despite less compute than RTX 5090. For dispatch overhead, backend choice is the dominant factor, although implementation choice also matters substantially within a backend (2.2 for Metal). In terms of dispatch vs kernel compute efficiency, we conclude that at batch=1 with the current dispatch-heavy pipeline, per-operation overhead dominates regardless of kernel quality. All code, benchmarks, and raw data are open source.
Figures & tables
| Experiment | Type | Dtype | Configs | Section |
| End-to-end LLM inference | ||||
| torch-webgpu | E2E | fp32 | 1 (RTX 5090/Dawn) | §4 |
| CUDA baselines | E2E | fp16, fp32 | 2 GPUs, 2 platforms | §4.2 |
| MPS baselines | E2E | fp16, fp32 | 1 (Apple M2) | §4.2 |
| CPU baselines | E2E | fp32 | 3 platforms | §4.2 |
| ONNX Runtime (WebGPU) | E2E | fp32 | 1 (RTX 5090) | §4 |
| Backend | Dtype | Tok/s | 95% CI | CV | TTFT (ms) | vs CUDA |
|---|---|---|---|---|---|---|
| Qwen2.5-0.5B-Instruct | ||||||
| CUDA (compiled, RTX 5090) | fp16 | 185.5 | [184.2, 186.8] | 0.9% | 5.4 | 1.00 |
| CUDA (eager, RTX 5090) | fp16 | 182.9 | [182.3, 183.5] | 0.4% | 5.5 | 0.99 |
| MPS (Apple M2) | fp16 | 47.8 | [47.7, 48.0] | 0.9% | 20.9 | 0.26 |
| torch-webgpu (fused, RTX 5090) | fp32 | 21.0 | [20.7, 21.4] | 4.0% | 41.6 | 0.11 |
| CPU (AMD Ryzen, eager) | fp32 | 13.7 | [13.4, 14.0] | 3.2% | 72.8 | 0.07 |
| Platform | Processor | Accelerator | Tok/s | 95% CI | CV | vs WebGPU |
|---|---|---|---|---|---|---|
| Native GPU (end-to-end inference) | ||||||
| Linux (primary) | RTX 5090 | CUDA | 185.5 | [184.2, 186.8] | 0.9% | 8.8 |
| macOS † | Apple M2 | MPS | 12.9 | [12.6, 13.2] | 5.5% | 0.61 |
| Windows 11 (laptop) † | RTX PRO 2000 | CUDA | 30.1 | [29.7, 30.5] | 3.3% | 1.4 |
| CPU (end-to-end inference) | ||||||
| Linux (primary) | AMD Ryzen 9800X3D | CPU | 13.7 | [13.4, 14.0] | 3.2% | 0.65 |
| Quantity | Value (ms) | Type | Source |
| Directly measured | |||
| TTFT (fused) | 41.6 | Measured | End-to-end benchmark |
| TTFT (unfused) | 71.4 | Measured | End-to-end benchmark |
| Per-dispatch cost | 0.024 | Measured | Sequential dispatch (exp6/exp7) |
| Well-constrained derived quantity | |||
| Per-operation overhead | 0.095 | Derived a | (71.4 41.6) / 312 fewer ops |
| Configuration | Dispatches saved | Tok/s | TTFT (ms) |
|---|---|---|---|
| No fusion (baseline) | — | 13.5 | 71.4 |
| + Fused RMSNorm (6 1) | 240/fwd | 19.4 | 46.6 |
| + Fused MLP gate+up+silu (3 1) | +48/fwd | 20.5 | 43.3 |
| + Fused K+V projection (2 1) | +24/fwd | 20.6 | 41.6 |
| Total improvement | 312 fewer | +53% | -41% |
| Implementation | Single-op ( s) | Sequential ( s) | Backend |
| Native implementations (dispatch benchmarks) | |||
| Dawn (RTX 5090) | 496.8 | 23.8 | Vulkan |
| wgpu (RTX 5090) | 35.8 | 35.8 | Vulkan |
| wgpu (AMD iGPU) | 24.8 | 24.5 | Vulkan |
| wgpu (Apple M2) | 48.3 | 71.1 | Metal |
| Browsers—practical (dispatch benchmarks; E2E via WebLLM in Table 13 ) | |||
| Implementation | Unfused (ms) | Fused (ms) | Speedup | Backend |
|---|---|---|---|---|
| wgpu (RTX 5090) | 0.101 | 0.072 | 1.41 | Vulkan |
| wgpu (AMD iGPU) | 0.106 | 0.063 | 1.67 | Vulkan |
| wgpu (Apple M2) | 2.03 | 2.13 | 0.95 | Metal |
| Chrome (RTX 5090) | 2.11 | 1.99 | 1.06 | Vulkan |
| Safari (Apple M2) | 0.20 | 0.22 | 0.91 | Metal |
| Operation | Dimensions | Time (ms) | TFLOP/s | % Peak † |
|---|---|---|---|---|
| MLP up projection | 896 896 4864 | 6.40 | 1.22 | 1.2% |
| MLP down projection | 896 4864 896 | 3.79 | 2.06 | 2.0% |
| Toy matmul | 256 256 256 | 1.10 | 0.030 | 0.1% |
| Optimization | Vulkan | Metal | Notes |
|---|---|---|---|
| RMSNorm fusion (6 1) | ✓ 1.4 | 0.95 | Helps Vulkan only |
| Tiled MLP (7 3 disp) | ✓ 1.17 | ✓ 2.0 | Significant on both |
| Command batching | minimal | minimal | Sync per token negates benefit |
Appendix figures & tables11 assets
Supplementary material from the paper’s appendix.
Appendix
| Category | Operations | Count |
|---|---|---|
| Linear (matmul) | Q, K, V, O proj, MLP | 169 |
| Multiply | RMSNorm weights, MLP gate | 220 |
| Add | Residuals, biases | 145 |
| SDPA | Attention per layer ( Dao et al., 2022 ; Dao, 2024 ) | 24 |
| SiLU | MLP activation | 24 |
| RMSNorm components | pow, mean, rsqrt | 147 |
| Platform | Backend | Mega (ms) | Multi (ms) | Speedup | -value | Result |
|---|---|---|---|---|---|---|
| RTX 5090 | Vulkan | 0.090 0.03 | 0.085 0.01 | 0.95 | 0.43 | Inconclusive |
| Apple M2 | Metal | 1.45 0.32 | 1.40 0.02 | 0.97 | 0.38 | Inconclusive |
| Dimensions (M K N) | Workgroups | Mean (ms) | Std (ms) | GFLOP/s |
|---|---|---|---|---|
| 256 256 256 | 16 16 | 1.10 | 0.09 | 30.4 |
| 896 896 4864 (MLP up) | 56 304 | 6.40 | 0.46 | 1216 |
| 896 4864 896 (MLP down) | 56 56 | 3.79 | 0.02 | 2055 |
| Platform | Browser | Model | Decode (tok/s) | Prefill (tok/s) | Backend |
| Windows 11 (RTX PRO 2000 Blackwell, 8GB) | |||||
| Windows | Chrome 144 | Qwen2.5-0.5B | 51.1 5.9 | 650 | D3D12 |
| Windows | Chrome 144 | Qwen2.5-1.5B | 45.7 6.3 | 350 | D3D12 |
| Windows | Firefox 147 | Qwen2.5-0.5B | 9.1 0.03 | 73 | D3D12 |
| Windows | Firefox 147 | Qwen2.5-1.5B | 9.1 0.03 | 55 | D3D12 |
| macOS (Apple M2, 16GB unified memory) | |||||
| Operation | Dimensions ( ) | (computed) | Regime at =1 |
| Qwen2.5-0.5B (896 hidden, 4864 intermediate) | |||
| Attention Q/K/V proj | 896 896 | 119 | Overhead-bound |
| MLP up projection | 896 4864 | 22 | Overhead-bound |
| MLP down projection | 4864 896 | 22 | Overhead-bound |
| Qwen2.5-1.5B (1536 hidden, 8960 intermediate) | |||
| Attention Q/K/V proj | 1536 1536 | 40 | Overhead-bound |
| Platform | Full Readback (ms) | Device Argmax (ms) | Improvement | -value |
|---|---|---|---|---|
| wgpu/Vulkan (RTX 5090) | 0.42 0.08 | 0.12 0.03 | +71% † | 0.35 |
| wgpu/Metal (Apple M2) | 1.59 0.12 | 1.69 0.15 | -7% | 0.62 |
| Optimization | Implementation | Isolated Result | E2E Impact |
|---|---|---|---|
| Kernel optimizations | |||
| Parallel softmax | Shared memory, 256 threads | 84 ( ) | Bottleneck removed |
| Tiled matmul | 16 16 tiles | 2–3 ( ) | 5% improvement |
| Overhead reduction attempts (null results) | |||
| Command batching | 16 dispatches per submit | 0% | No effect ∗ |
| Buffer pooling | Size-class reuse | 0% | No effect |
| Metric | CUDA | WebGPU (Vulkan) |
|---|---|---|
| Kernel launch/dispatch overhead | 7.4 9.2 s | 24–36 s |
| Overhead ratio | 3–5 (WebGPU higher) | |
| RMSNorm unfused | 21.3 s | — |
| RMSNorm fused | 23.2 s | — |
| RMSNorm compiled (torch.compile) | 20.9 s | — |
| Fusion speedup | 0.92 ( no benefit ) | |
| Metric | 0.5B (measured) | 1.5B (measured) | Scaling | Source |
|---|---|---|---|---|
| Layers | 24 | 28 | 1.17 | Model config |
| Ops/forward (fused) | 564 | 658 a | 1.17 | Scaled by layers |
| WebGPU tok/s (fused) | 21.0 | 17.9 | 0.85 | Measured (30 runs) |
| WebGPU tok/s (unfused) | 13.5 | 10.4 | 0.77 | Measured (30 runs) |
| WebGPU TTFT fused (ms) | 41.6 | 51.3 | 1.23 | Measured |
| WebGPU TTFT unfused (ms) | 71.4 | 87.9 | 1.23 | Measured |
| Platform | Unfused | Tiled | Mega | Tiled Speedup | -value † |
|---|---|---|---|---|---|
| (7 disp) | (3 disp) | (1 disp) | vs Unfused | ||
| wgpu/Vulkan (RTX 5090) | 0.72 ms | 0.62 ms | 0.32 ms | 1.17 | 0.01 |
| wgpu/Metal (Apple M2) | 5.74 ms | 2.85 ms | 1.48 ms | 2.01 | 0.001 |
| Operation | Total ( s) | Per-dispatch ( s) |
|---|---|---|
| Encoder create | 644.9 | 6.4 |
| Pass begin | 317.1 | 3.2 |
| Set pipeline | 144.9 | 1.4 |
| Set bind group | 99.2 | 1.0 |
| Dispatch call | 63.9 | 0.6 |
| Pass end | 66.6 | 0.7 |
LLM Inference Efficiency
Large language model inference efficiency reduces the time, memory, energy, and cost of generating useful outputs.
See all 352 papers