Repository navigation
vulkan : WMMA selected-key attention for QSA block selection - #133
Conversation
flash_attn_sel ran scalar QK and PV, and every workgroup bitonic-sorted the whole selection row. On gfx1151 (Flash-Next REAP-320, pp2048 at depth 12000) one QSA attention op took 68 ms; the masked per-cell gather branch took 13-14 ms for the same layer. Same op, same attended keys: - flash_attn_sel_prep.comp cleans each selection row once (not once per K/V head and split): it drops invalid entries and repeated cells (a shared-memory hash, first occurrence kept), keeps the survivors in their order, pads the row with a live cell and stores the count. Both attention kernels read the cleaned rows, so the scalar kernel loses its sort and its 16 KiB sorted row (shared memory at GQA 12: 63,104 -> 46,720 bytes). - flash_attn_sel_cm.comp (RADV, gfx11 WMMA layout): one 64-lane subgroup per (query, K/V head). The GQA heads are the 16 columns of every tile, keys go in steps of 16: S^T = K Q^T and O^T += V^T P^T, so each head's softmax state lives in the lanes of its column, with no shared memory or barrier in the key loop. K and V fragments are built in registers from the gathered rows with the gfx11 WMMA layout (as GATHER_FRAG does): K in 16-byte loads, V in 16-byte loads that each fill one element of 8 tiles (the output store undoes that dim permutation). Padded columns read a live row and score -inf, so no load is bounds-tested. The rescale of O is skipped when no head's max changed. The K/V heads of a query are neighbours in the grid, so they run together on the same cells. 8.4 KB shared memory, 192 VGPRs. - Pipeline gate: 64-lane subgroups must be available (required size within min..max, or 64 by default without size control), plus subgroup arithmetic and fp16; shared memory is checked against the device limit. The WMMA kernel needs RDNA3 + RADV, coopmat 16x16x16 f32-acc, ballot and 16-byte aligned K/V; otherwise the scalar kernel runs. Only tested on gfx1151. GGML_VK_SEL_CM=0 forces the scalar kernel. Perf logger, FA per QSA op at d12000 (kv 14080, 2048 queries): 68.2-68.6 ms -> 8.0-8.4 ms. Kept/dropped steps: - WMMA kernel: 9.7-14.0 ms. With every gather pointed at one row it took 5.6 ms, so about half of the time was the memory side. - rescale skip: 149.8 -> 144.6 ms summed over 12 ops (kept, cheap). - K/V heads adjacent in the grid: 9.8-13.8 -> 8.0-8.4 ms (kept). - V in 8-byte quarter loads: still 192 VGPRs, more instructions, same time (dropped). - Q and P split into f16 hi + lo (near-exact, NMSE 1.7e-10): 13.6-13.9 ms, and the same Flash-Next KLD as plain f16 (dropped). llama-bench pp2048 ub2048 ABBA, 4 samples per arm (base 4429170): d0 782.3 -> 776.7 (kernel not used), d12000 568.4 -> 710.6, d32000 537.8 -> 678.7; tg128 at d32000 21.80 -> 22.36. Tests (test-backend-ops -b Vulkan0): FLASH_ATTN_EXT 5344/5344, QSA_PREFILL 22/26 and QSA_DECODE 82/92 as on the base (the poison cases), QSA_PREFILL_MASKLESS 13/13 and QSA_DECODE_MASKLESS 33/33, the same with GGML_VK_SEL_CM=0 and with the base kernel. New cases: complete-block rows (512 blocks of 4 cells + tail, partial and empty rows, scattered cells), GQA 4/8/12, caches of 32768 and 65536 cells. A wrong output permutation in the WMMA kernel fails 15 prefill and 16 decode cases. Flash-Next c8192: PPL 4.0081 -> 4.0378, KLD 0.0271 (top-1 93.8%). The near-exact hi/lo variant gives KLD 0.0261 and PPL 4.0067, so this is the model's response to any non-bit-identical attention output (later selections flip), not f16 error. c4096: 3.9289 -> 3.9352. Assisted-by: Claude Opus 5.5
|
Independent verification on a second Strix Halo (strix-halo-002, gfx1151, RADV) Built CorrectnessFull QSA suite,
All pass. The maskless tests are the strong ones here: their The WMMA path is really usedI temporarily printed ReviewThe two pieces look right to me:
Points worth considering, none blocking:
I did not reproduce the end-to-end prefill t/s or the KLD; only the op-level tests and the oracle. CI
LGTM. The WMMA kernel is exercised on gfx1151, matches the FP64 oracle by ~4e-8, and the scalar fallback is preserved. |
|
Thanks for the oracle numbers and for confirming the WMMA pipeline is really selected. On your three points:
|
dzannotti
left a comment
There was a problem hiding this comment.
Verified on Strix Halo (gfx1151, RADV), current master ad219f329 vs master + this PR. Qwen3.8-Flash-Next GSQ-RCO-Q2_0, -fa 1 -b 2048 -ub 512, ABCCBA.
| test | master | PR | Δ |
|---|---|---|---|
| pp2048 | 596.2 | 596.0 | ±0 |
| pp2048 @ d12000 | 458.9 | 544.3 | +18.6% |
| pp2048 @ d32000 | 433.4 | 521.9 | +20.4% |
| tg64 @ d32000 | 25.7 | 26.6 | +3.6% |
Correctness:
- QSA_PREFILL_MASKLESS 13/13 and QSA_DECODE_MASKLESS 33/33, with WMMA and with
GGML_VK_SEL_CM=0. - QSA_PREFILL, QSA_DECODE and QSA_EXPAND pass. FLASH_ATTN_EXT 5344/5344, same as master.
- KLD against master at 8k context: 0.0011 (PPL ratio 1.0002). Against the HIP reference, master's Vulkan is at 0.00244 and this PR at 0.00249, so no measurable loss.
- The scalar fallback gives master's output exactly (KLD 0).
Two small follow-ups: put the prep pipeline (~34 KB shared memory) under the same shared-memory check as the scalar kernel, and track the RADV-layout self-check you mentioned, since the WMMA fragment layout isn't version-guarded.
Comment generated via automated review of clanker.
Stacked on #119 (and #115 under it); only the last commit is new here. This makes the selected-key attention from #119 faster on Vulkan. The change is limited to the selected-key dispatch and its pipelines.
Two pieces:
GGML_VK_SEL_CM=0forces the fallback.On a Strix Halo (gfx1151, RADV) with Flash-Next, the attention op at 12k depth goes from about 68 ms to about 8 ms, and pp2048 goes from 568 to 711 t/s at 12k and from 538 to 679 t/s at 32k. Depth 0 doesn't use this path and is unchanged. Decode at 32k is slightly faster (21.8 to 22.4 t/s).
Perplexity moves within the error bars. The scalar fallback gives identical output to #119. The WMMA kernel sums in a different order, which gives a KLD of about 0.027 against #119 on Flash-Next. A near-exact variant I tried (hi/lo split) gave 0.026, so that looks like this model's floor for any change in summation order rather than precision loss. New test cases cover complete, partial and empty rows, GQA 4/8/12, and 32k/64k cells; scrambling the output order makes them fail.
Written with Claude, tested by me.
Assisted-by: Claude Opus 5.5