Repository navigation
Conversation
…dow's rows share each chunk's K/V in L2 tf_q35_attn_partial and tf_q35_attn_partial8 launched (chunks, key heads, rows), so every row of a verify window or prompt chunk re-read its keys and values from DRAM (33.6 MB a layer at 8k, 134 MB at 32k, past GB10's 24 MB L2). The grid is now (rows, key heads, chunks); each block's work is unchanged, so the bits are too. The kernel contract registers partial + merge for bf16 and fp8 caches, bit-equal to each row launched alone (the old grid's blocks), with a control that drops each row's last chunk, and records a pre-existing finding: the merge skips a chunk whose l is NaN, so a NaN key in one of several chunks leaves the row finite.
Owner
|
Thanks @jschmied. This is on
Closing as landed; it ships in 1.1.4. As you noted, #1168's tensor-core attention will replace these kernels, and the two are being rebased together. - Synthema, Ash's AI Assistant. |
Owner
|
This shipped in TensorFold 1.1.4: https://github.com/ashhart/TensorFold/releases/tag/v1.1.4 Thank you @jschmied for the contribution. - Synthema, Ash's AI Assistant. |
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.
tf_q35_attn_partial(and_partial8for--kv-cache fp8) launches a grid of (chunks, key heads, rows). Blocks are dispatched with x fastest, so the GPU walks every chunk of row 0, then every chunk of row 1, and so on. Each row's blocks read the whole of its keys and values again. At head dim 256 a 27B attention layer holds 33.6 MB of K/V at 8k tokens and 134 MB at 32k, more than GB10's 24 MB L2, so every row of a DFlash2 verify window (12-16 rows) or a 128-row prompt chunk re-reads K/V from DRAM.This PR swaps the axes to (rows, key heads, chunks): all rows of a chunk run together and read its keys from L2. Each block still computes exactly what it computed before (same row, head, chunk, same loop), only the order the blocks start in changes, so the bits are unchanged.
The diff:
blockIdx.xandblockIdx.ztrade places in both kernels, andcuda_forward.ziglaunches{ total, kv_heads, max_chunks }. Rows move togrid.x, which also lifts the 65,535 capgrid.zhad on them.Synthetic kernel, L2 flushed before each launch (32k keys): 16 rows 7.62 -> 4.67 ms, 128 rows 72.1 -> 29.3 ms. ncu L2 hit rate 22.6 % -> ~100 % at 16 rows.
Served Qwen3.8-27B MLX 4-bit + DFlash2, GB10.
--parallel 4 --context 49152 --prompt-cache-gib 8, bf16 cache. A fresh server per arm, main and branch alternating, two rounds.The gain grows with context and with rows a round: at 8k the K/V is close to L2-sized and the change is 0-3 %.
Checks
--kv-cache fp8arms: 8 of 8 equal.contract_q35_attn.zig): partial and merge as one call, against float64 head by head, bf16 and fp8 caches.SUMMARY 142 kernels: 142 pass gates 1-4, 0 fail, 2 known findings; 33 controls: 33 red as planted, 0 missed.zig build test -Dnvcc=/usr/local/cuda/bin/nvcc: exit 0 (295/295 steps; 1,816 of 1,827 tests passed, 11 skipped). lean_check: 0 new against the merge base.zig fmt --checkis clean.Gotchas
qwen27-attn-rows-first@74020261, one commit onmain@f4d6c4f23.attn_rowskernel groups a long stream's rows so each K tile is read once, which covers this change and more, but it changes replies (~1e-4 RMS). This PR is the bit-exact step formainuntil qwen CUDA: decode attention on tensor cores (fp8 and bf16 caches), decode after long prompts 1.5-2.3x faster #1168 lands; if qwen CUDA: decode attention on tensor cores (fp8 and bf16 caches), decode after long prompts 1.5-2.3x faster #1168 lands first, drop this one. The two conflict textually inqwen35.cu,qwen35_kv8.cuand thecuda_forward.ziglaunch line.tf_q35_attn_mergeskips a chunk unlessPL > 0, and NaN fails that test. The contract registers it asknownat gate 1; with that one plant removed, gate 1 passes for both caches.qwen35*launches whose 13.0 records are still pending (usage none). That predates this change, and none of it is new here.