[ExecuTorch][WebGPU] Make shader workgroup sizes runtime-configurable#20954
[ExecuTorch][WebGPU] Make shader workgroup sizes runtime-configurable#20954JCNTH wants to merge 2 commits into
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/20954
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit fb95a32 with merge base e500fee ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
This PR needs a
|
|
@claude Review this PR |
|
Claude finished @JCNTH's task in 2m 54s —— View job PR Review: WebGPU runtime-configurable workgroup sizes
This is a clean, well-scoped refactor. The I reviewed statically (no WebGPU device build here). A few notes below — nothing blocking. Observations1. The power-of-two invariant is documented but not enforced (latent hazard) Each tree-reduction kernel now carries: // wg_size must be a power of two (the tree reduction halves the stride).
override wg_size: u32 = 64u;This is correct — return std::min(desired, limits.maxComputeInvocationsPerWorkgroup);Today this is always safe: the default is 64, the spec floor for Suggestion: a debug assert / comment at the call sites for the reduction kernels (rms_norm, sdpa_softmax, coop4_bicol) noting the pow2 requirement, or a small 2. const uint32_t gemv_wg_size =
utils::clamp_workgroup_size(device, kQ4gswLinearCoop4BicolWorkgroupSizeX);This runs a second 3. The softmax dispatch now passes a clamped 64 instead of the sentinel 4. Override-sized workgroup arrays — e.g. WGSL permits an override-expression as a VerdictLooks good to merge. The only item I'd genuinely consider addressing is (1) — it's a latent footgun that the "make it tunable" framing invites, even though every path is safe at the current default. (2) and (3) are informational. |
Stack from ghstack (oldest at bottom):
Instead of hard-coding each compute shader’s workgroup size, make it a WGSL
override wg_sizeset at pipeline creation via a hostWGPUConstantEntry(mirrors the landedaddop). One WGSL per kernel; each distinct size becomes its own Dawn-cached pipeline — so the size can be tuned per device/shape WITHOUT generating another shader variant.Key changes:
rms_norm.wgsl/sdpa_softmax.wgsl/q4gsw_linear_coop4_bicol.wgsl(the free-knob reduction + decode-GEMV kernels) —const WG*->override wg_size; shared arrays, tree-reduction strides, and@workgroup_sizeall use it; handlers wire it fromclamp_workgroup_size(...).QuantizedLinear.cpp— split GEMV out offixed_wgso it takes the override; steel (256) + shmem (64) stay fixed.q4gsw_linear_gemm_shmem.wgsl— itsoverride wg_sizewas a false knob (geometry hard-locked to 64, never host-wired) -> plainconst.q4gsw_linear_gemm_steel.wgsl,sdpa_fd_decode/sdpa_fd_split.wgsl,sdpa_fd_reduce.wgsl) — their size is bound to tile/head-dim geometry, not a runtime knob._wgsl.hheaders.Behavior is identical at the default 64:
clamp_workgroup_sizeonly reduces towardmaxComputeInvocationsPerWorkgroup(spec floor 256), so 64 is emitted; dispatch counts are unchanged.Co-authored-with: Claude Code.
@exported-using-ghexport
Differential Revision: D112060863
Differential Revision: D112060863