Skip to content

Indirect dispatch in Kernel; ShunPerm (parallel Fisher-Yates) on Gridwise - #87

Merged
jowens merged 3 commits into
mainfrom
indirect-dispatch-shun
Oct 27, 2026
Merged

jowens merged 3 commits into
mainfrom
indirect-dispatch-shun

Conversation

@jowens

@jowens jowens commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Indirect dispatch in Gridwise's Kernel, and Shun et al.'s parallel Fisher–Yates ported onto Gridwise using it. This comes after #84–#86, all merged.

Indirect dispatch (core)

  • Kernel option indirect: "args" (or { buffer, offset }). The kernel then dispatches with dispatchWorkgroupsIndirect, reading the workgroup counts (x, y, z: three u32s) from that buffer when the GPU runs it. An earlier kernel can size a later one without a trip to the CPU. A buffer without GPUBufferUsage.INDIRECT is a clear error. Pipelines, bind groups, timing and trials work as before.
  • WGSL helper indirectDispatch, used via include(). It writes the counts, splitting a 1D count across x and y to stay within maxComputeWorkgroupsPerDimension; as far as I know, Dawn silently skips counts above the limit. The dispatched kernel linearizes its workgroup id with computeLinearizedGridParametersSplit and skips ids at or past the count. A count of 0 dispatches nothing.
  • BasePrimitive.singleTrialOnly. It's for primitives whose kernels can't be repeated in place, such as a round that appends to a list:

ShunPerm (src/shunperm.mjs)

Shun, Gu, Blelloch, Fineman and Gibbons, SODA 2015.

  • Algorithm: pending swaps reserve both locations with atomicMax, then commit the swaps that own both. The output is bit-identical to sequential Fisher–Yates with the same swap targets, on any GPU and in any run. reference() computes it on the CPU.
  • Rounds: the number of rounds (about 3 log₂ n) is only known on the GPU. So maxRounds rounds (default ceil(3 log2 n) + 16) are recorded up front, and before each round a one-invocation kernel sizes that round's indirect dispatch from the number of iterations still pending. There are no CPU round trips, and rounds after the last dispatch no workgroups. roundsUsed() reports how many rounds were needed.
  • Built from Gridwise's pieces: declared buffers, UniformStruct, include(), random.mjs. So it also takes the Philox option (rng), as MultisplitPerm does.
  • Same output as the paper's hand-written port: its CPU reference is identical to the paper's ShunPerm.sequential for 1,000, 2^20 and 100,003 elements. The paper's Shun results therefore carry over.
  • Also: exported and typed, documented in docs/random-permutations.md, and added to misc/benchmark_node.mjs as shun.

Tests

  • Indirect dispatch: a kernel writes counts 0, 5 and maxComputeWorkgroupsPerDimension + 3 (which needs a second dimension), and the indirectly dispatched kernel checks how many workgroups ran and the largest id.
  • ShunPerm: bit-exact against reference() for 2, 1,000 and 100,003 elements and Philox-7 at 16,384, finished within maxRounds, and trials: 2 refused. Plus 2^20 in the large tests.

Checked

  • Simulated RDNA4: 89 of 89 pass.
  • Lavapipe: the full suite with timing and large tests passes except the existing 8-lane sort failures, and ShunPerm 2^20 passes with timing (warm-up included).
  • Without subgroups: ShunPerm passes, in 22 rounds for 1,000 elements and 40 for 100,003.
  • Package test: passes.

Not done here

  • Re-vendoring into the paper repo. I'd do that once this merges, so the paper's bench uses ShunPerm from Gridwise instead of its own copy.
  • Fewer compute passes. Each round is three Kernels, and Gridwise records each as its own compute pass, where the paper's port puts everything in one pass. If that shows up in timings, a later option could let consecutive kernels share a pass.

Generated by Claude Code

@jowens
jowens merged commit 06c4a00 into main Oct 27, 2026
4 checks passed
@jowens
jowens deleted the indirect-dispatch-shun branch October 27, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants