concept-collection / math-webgpu-sandbox
math-webgpu-sandbox / README.md
99 lines · 4.5 KBCodeBlameHistory
3Write a MATLAB script, run it on your GPU. The sandbox compiles MATLAB-syntax
4scripts to fused WebGPU compute kernels, times them with the script's own
5`tic`/`toc`, and — because everything you write is plain MATLAB — you can
6paste the same script into real MATLAB and compare the numbers. An optional
7in-browser CPU run through [numbl](https://numbl.org)'s normal engine gives a
8third column without leaving the page.
10**Live page:** https://concept-collection.github.io/math-webgpu-sandbox/
12```matlab
15y = zeros(n, 1);
16tic;
e01ddf1MATLAB-syntax scripts on WebGPU: fused kernels, tic/toc timing, CPU comparisonJeremy Magland 18 y = y + 0.1*sin(x + k) .* exp(-x) + x.^2;
19end
20toc
21fprintf('checksum %.4f\n', mean(y));
22```
02f2376Scale examples to 1-4 s of GPU work so tic/toc comparisons are meaningfulJeremy Magland 24That loop body is **one** GPU kernel, compiled once and replayed 600 times —
25about five billion element-updates, a few seconds on an integrated GPU.
27## How it works
9c655b8Remove CPU comparison run and timing table; tighten footnoteJeremy Magland 29The script is parsed and lowered by numbl's JIT pipeline (reached through a `numbl-src` vite alias, the same
e01ddf1MATLAB-syntax scripts on WebGPU: fused kernels, tic/toc timing, CPU comparisonJeremy Magland 30arrangement [turing-surface](https://github.com/concept-collection/turing-surface)
31uses), which fixes every type and shape at compile time — `n = 2048;
32A = rand(n);` pins static shapes via exact-value propagation. The back end is
33this repo's: a planner maps the typed IR onto WebGPU, and an executor replays
34the resulting op sequence.
36- **Fusion.** numbl's inline pass folds single-use temps back into their
37 consumer, and a sandbox-side pass (`src/mgpu/fuse.ts`) folds the rest —
38 transcendentals, comparisons, logicals — which numbl's C backend declines
39 but WGSL handles. One source line becomes one kernel. Generators fuse too:
40 `x = 2*rand(n,1) - 1` is a single kernel that hashes its way to uniform
41 variates per element, touching no other buffer.
42- **Reductions** (`sum`/`mean`/`prod`/`max`/`min`/`norm`/`dot`) take a fused
43 *loader*, so `sum(a.*b + c)` reads its operands exactly once. Vectors (and
44 `X(:)`) reduce fully in two passes; matrices reduce per column, which in
45 MATLAB's column-major layout is the contiguous direction.
46- **`A * B`** is a 16×16-tiled shared-memory GEMM (column-major, adapted from
47 [matmul-bench](https://github.com/concept-collection/matmul-bench));
48 matrix transpose is a tiled relayout; vector transpose, `X(:)` and
49 `reshape` are views of the same buffer (free) when the source is never
50 reassigned.
51- **`for` loops replay, they don't unroll.** The body is planned once; the
52 loop variable lives in a dynamic-offset uniform with one slot per
53 iteration, and all iterations are encoded into one submit. `rand` inside a
54 loop mixes the iteration counter into its stream, so every pass draws
55 fresh values.
56- **`tic`/`toc` are synchronization points**: pending GPU work is submitted
57 and awaited, then wall-clock time is taken on the host. That is the same
58 thing MATLAB's synchronous tic/toc measures, which is what makes the
59 number comparable when you paste the script there.
61## What is (and isn't) supported
63Supported: elementwise math on real arrays (including comparisons, `&`/`|`/`~`,
64two-arg `max`/`min`, `mod`/`rem`, `.^`), `zeros`/`ones`/`eye`/`rand`/`randn`/
65`linspace`/ranges, `A*B`, transpose, the reductions above, `A(:)`/`reshape`,
66counted `for` loops, `tic`/`toc`, `disp`/`fprintf`, semicolon-suppressed or
67echoed assignments, and literal row/matrix constants.
69Deliberately rejected, with a source-located error rather than a wrong
70answer: indexing/slicing beyond `(:)`, `if`/`while`, complex numbers,
71user-defined functions, variables that change size, and printing inside `for`
72loops (the body has nowhere to run host I/O — it replays on the GPU).
74## The comparison is honest, with two caveats
76- The GPU computes in **f32**; WebGPU has no f64. MATLAB defaults to double.
77 Timing comparisons are still meaningful; for the closest apples-to-apples,
78 use `single` arrays in MATLAB. Values agree to single precision, and the
79 scripts print checksums so you can see that they do.
80- `rand`/`randn` here are deterministic counter-based generators
81 (PCG-flavored hash of element index and call site). Statistics match
82 MATLAB's; individual draws do not, so checksums of random data are close
83 but not equal.
85## Development
87```
88npm install # numbl must be checked out as a sibling: ../../numbl
89npm run dev
90npm run test:node # correctness suite on desktop WebGPU (Dawn)
91npm run test:gpu # same suite in headless Chrome (SwiftShader fallback)
92```
9c655b8Remove CPU comparison run and timing table; tighten footnoteJeremy Magland 94The GPU compiler runs from numbl's TypeScript sources directly (through the
95`numbl-src` alias), so no numbl build is needed.
97## License
99Apache-2.0