Browser client: WebGPU backend with a CPU/GPU selector - #105
Open
wasabipesto-bot wants to merge 2 commits into
Open
Browser client: WebGPU backend with a CPU/GPU selector#105wasabipesto-bot wants to merge 2 commits into
wasabipesto-bot wants to merge 2 commits into
Conversation
WebGPU has no shader-int64, so a browser's wgpu device rejects every existing kernel. This one is the same detailed algorithm with no u64 anywhere: multi-precision values as 16-bit halves in u32 words (schoolbook accumulation provably fits u32), digit masks as u32 quads, and the split16 scan the wgpu targets already use. Batches are 4M candidates and flushed per submission — sized for slow integrated GPUs behind browser watchdogs. The host path is async-first like the native backend, over the same context, drain helper, and conservation check. Parity is anchored the same way too: exact CPU agreement on lavapipe — which drives the identical naga/WGSL path a browser uses — at bases 10/40/62/80 and 97, the widest supported base (4 limbs, four-mask digit set), which no other device test exercises. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… end The page gains a Compute Backend dropdown: CPU keeps the existing worker pool; GPU appears when a WebGPU adapter initializes, named after the adapter, and runs whole fields in one dedicated worker (the device supplies the parallelism) through the u32 kernel via process_chunk_gpu/gpu_init wasm bindings. Claims are sliced ~32 ways for progress ticks and stop-responsiveness; results merge through the same server-format path as the CPU workers. Also fixes the CPU worker reading distribution_updates, a field name FieldResults has not serialized for some time — the checked-in page only worked against a stale pkg build. wasm-client/e2e is the end-to-end harness: it serves web/search, drives the real page in the playwright container's headless Chromium, runs the offline benchmark on both backends, and asserts their histograms agree exactly. SwiftShader supplies the WebGPU adapter, so the whole browser GPU stack (wasm -> CubeCL -> WGSL -> WebGPU) runs in CI-shaped environments with no GPU hardware. serving /repo/web/search at http://127.0.0.1:39397/ === CPU backend === Benchmark processing completed! === GPU backend === Benchmark processing completed! CPU and GPU histograms agree exactly runs it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runs the browser client on the GPU through WebGPU, with a backend selector on the page, and adds an end-to-end test that exercises the whole browser stack in CI-shaped environments with no GPU hardware.
Stacked on #99 (merged); the core prep landed there, so this PR touches the backend only twice: one visibility change and one module registration.
The kernel
WebGPU has no
shader-int64, so every existing kernel is rejected by a browser's wgpu device.common/src/cubecl_web.rsis the detailed algorithm with no u64 anywhere:(2^16-1)^2 + 2*(2^16-1) < 2^32, pinned by a unit test)Structure, comments and naming track the native kernel line for line, so the two review side by side. Batches are 4M candidates, each flushed as its own submission — the same watchdog rationale as #99's
ffe33a6, and doubly so in a browser tab.Correctness
Exact CPU parity on lavapipe, which drives the identical naga→WGSL path a browser uses:
Base 97 is the widest supported base and no other device test in the tree exercises it.
The page
The existing page keeps its structure — same histogram, same rate/statistics, same claim→process→submit flow. What is new:
Also fixes a real pre-existing bug: the CPU worker read
chunkResult.distribution_updates, a fieldFieldResultshas not serialized for some time. The checked-in page only worked against a stalepkg/build; anyone rebuilding it got an empty histogram.Testing it end to end
wasm-client/e2e/(orjust wasm-e2e) servesweb/search, drives the real page in the Playwright container's headless Chromium, runs the offline benchmark on both backends, and asserts their histograms agree exactly:The GPU arm is real: Chromium's SwiftShader supplies a software WebGPU adapter, so wasm → wasm-bindgen → CubeCL → WGSL → WebGPU all execute — no GPU, no host browser, nothing but docker. Between this and the lavapipe suite, three independent implementations agree on the same field: native CPU, browser CPU wasm, and browser WebGPU.
Known limitations
std::thread::scopeMSD filter, which is not browser-shaped; the mode selector is unaffected because the browser client only ever claims detailed fields.pkg/remains a build artifact (just wasm-build), unchanged from before.