Repository navigation
Conversation
…to back so they share it in L2 The attn_decode grid becomes (rows, heads, slices); each work-group's arithmetic is unchanged, so outputs are bit-identical (refs ashhart#2543).
…ld (slices, heads, rows) grid It launches that grid only where it stays inside the buffers (no more slices than rows), so gate 3 goes red at 16 rows over 33 keys and the registration guards the launch order forward.zig uses. Co-authored-by: SergiioB <119968745+SergiioB@users.noreply.github.com>
…and its unrun cases Co-authored-by: SergiioB <119968745+SergiioB@users.noreply.github.com>
…ce a round on bf16 DPAS (opt-in)
…, 329-item battery)
SergiioB
marked this pull request as draft
November 13, 2026 13:58
Author
|
Note 🤖 Claude Fable 5 responding on behalf of SergiioB Closing this: it changes tokens under its switch, and #2543 (10 Nov) rules that out even as an opt-in. It was opened from the 8 Nov answer without reading the later one; that was our mistake, not a challenge to the rule. What stays useful from it, all with main's tokens:
The kernel stays out of tree. Receipts remain on the branch |
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.
What this changes
Long-context decode on the Qwen3.8-27B XPU path is slow because every tree row of a round scores the whole prefix in scalar fp32: 15.1 tok/s at 131K prompt tokens on #2595, against 127 at a short prompt. With
XPU_ATTN_PREF=256a round reads the committed prefix once, on bf16 DPAS, for 8 (row, head) queries at a time: 50.7 tok/s at 131K, 90.1 at 32K, 114.7 at 8K. It is off by default; unset, decode runs today's kernels and token hashes equal main's.The switch changes tokens: it sums the same products in another order and keeps attention weights in bf16, as
attn_promptdoes. Drafted output equals"draft": falseunder it.Correction, same day: this pull request does not meet the rule you set in #2543 on 10 Nov ("a speedup has to keep main's tokens, even as an opt-in"). I opened it from the 8 Nov answer there and missed the later one; the first version of this description called it "the opt-in agreed in #2543", which was wrong. I have moved it to draft. It stays up only as evidence in case the numbers below are a reason to look at that rule again for a switch that is off by default, as
XPU_KV_INT8is. If the rule stands, close it and I will keep the kernel out of tree. Two exact variants were tried and neither helps: oneexpa key inattn_decodekeeps every token hash and is 1 % slower, and carrying P in two bf16 parts does not bring main's tokens back.078cac06b). This adds four commits:c7f5f11fd(kernels and launch),c7c1b2241(docs),9e78a0fe5andaa19975fd(receipts).atc overlap --json: not run,atcis not installed on this machine. By hand: xpu: a sampled Qwen3.8-27B row draws from a top-k kept on the card #2895 also editszig/src/xpu/dev.zig,forward.zigandqwen27.zig, and XPU: Qwen3.8-27B attention merge with 16 subgroups per head, bit-identical #2799 editsattn_mergeindecode.cl. This change adds lines beside theirs (new kernel fields, one branch around theattn_decodelaunch, an#includeat the end ofdecode.cl) and leavesattn_mergealone.How it works
pref_base(pos, CH) = ((pos - 16) / CH) * CH: the row atpostakes its keys below that from the prefix chunks and the rest (at mostCH + 16) from slices. The cut depends on the row's position alone, and a tree row is at most 15 below its round'sp0, so the chunks hold committed keys only and a drafted row cuts where the same row decoded serially does.attn_pref: one subgroup per (tile of 8 queries, K/V head, chunk ofCHkeys). Q·K onbf16_bf16_matrix_mad_k16, online softmax 16 keys a step, P in bf16, P·V on the same DPAS. fp32 partials a chunk.attn_tail:attn_decode's body frompref_baseon. The body moved intoattn_slices, whichattn_decodecalls with a constant 0, so its signature and its contract registration are unchanged.attn_merge2: merges a row's chunks, then its slices, in key order.XPU_KV_INT8=1, and tree rounds of several streams, keep the default path under the switch.Checks on this head
aa19975fd.078cac06band 116 on this head; 0 new.python3 tools/pr_check.py --base 078cac06b: 0 errors, 1 advisory warning (no--prnumber yet).xpu-kernel-contract-limits(no GPU):PASS: every registered launch fits bmg-g31, every record current, every control red.tf-xpu-contract-run --device 0onaa19975fd:SUMMARY bmg-g31 0xe223 10 kernels: 10 pass gates 1-4, 0 fail, 0 known findings; 7 controls: 7 red as planted, 0 missed; 0 limit problems, exit 0.attn_decode+attn_mergestay bit-equal to the upstream pair after the move intoattn_slices.zig build test,test-golden,xpu-qwen27-tests.Receipt
docs/receipts/xpu-qwen27-attn-prefix/holds every timed request (requests.json) and the graded battery (battery.json).token_shaequals XPU 27B decode attention: tree rows of a key slice run back to back (bit-identical, +23 % at 32K, +33 % at 131K) #2595's main column at every prompt length (26 requests), so it stands for main in the table.XPU_ATTN_PREFis set.XPU_ATTN_PREF=CH, unset by default. Accepted: a multiple of 32 from 64 to 4096; anything else stops the load. No profile row.TensorFold/Qwen3.8-27B-MLX-4bit@22d8d538, drafterz-lab/Qwen3.8-27B-DFlash2.--parallel 1 --context 139264 --prompt-cache-gib 0 --no-thinking, greedy, 512 tokens, one stream, one discarded warmup a cell. The speed table was measured ona1d896a88with these kernels insidedecode.cl; this head moves them todecode_prefix.cland returns the sametoken_shaon both paths at 8K and 32K (16 requests on B70 Cannot get more than 8% GPU utilization on M4 with 48 gb (even using --resident-budget 30 GiB for example) #2)."draft": falseequals a second drafted run at 68 / 7,976 / 32,552 tokens (two repeats) and 130,856 (four), code and prose, and on the 275 battery items run with"draft": false(275 of 275; the other 54 were not run that way). The second card returns the first card's drafted text on 329 of 329 items.XPU_ATTN_PREF=256"draft": false: 30.4 / 23.7 / 13.0 default and 30.4 / 27.3 / 18.8 with the switch at 8K / 32K / 131K. The two repeats at 8K and 32K agree within 0.05 tok/s; four at 131K give 50.70 to 50.79 (code) and 45.64 to 45.75 (prose). Correction (this row first read 1.00, "the same kernels"): that was wrong. A 512-token answer passes position 272, where the switch starts, and on B70 #2 in one session the switch is slower at a 68-token prompt: 123.3 / 98.6 default against 122.3 / 96.7 drafted (−0.8 % / −1.9 %), and 31.3 against 30.4 with"draft": false(−2.9 %). I am measuring a fix now: rows below position 1,040 stay on the default slices, so short contexts run today's kernels and return today's tokens. The cut still depends on the row's position alone. I will push it with its numbers and say here if it does not remove the loss. On B70 #2 at 180 W, this head: 85.0 to 109.0 at 8K and 42.3 to 84.5 at 32K (code), while the other card was serving.XPU_ATTN_PREF=512against 256 differs again at 3 of 4 cells, so the text follows the order of the sums, not the weights' precision: a variant that carries P in two bf16 parts (16 significant bits) did not bring the default text back and was 2–12 % slower.attn_prompt. Cold TTFT at 130,856 tokens is 134.0 s on both.Not done, and what I propose for the gate
On 8 Nov #2543 asked an opt-in for an FP64 attention reference, teacher-forced error and margins, its own contract records and drafted equal to
"draft": false. Only the last is here, and the 10 Nov rule comes before all of it.attn_pref+attn_tail+attn_merge2as one operator against the float64 attention ofxpu_attn_ref.zig, withstore = bf16for P, and a planted control (a merge that drops the last prefix chunk). Gate 4 needs your call: P·V sums bf16 weights on DPAS, asattn_promptdoes.tools/bench_openai.py, prompt-cache resumes under the switch, sampled decoding.If you'd rather see 1 and 2 before any review, say so and I'll keep this as is until they are in.
Revert: unset
XPU_ATTN_PREF(the default), orgit revertthe four commits; no format or public interface changes.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. Drafted equals"draft": falseat every cell and on 275 battery items; resumed and concurrent were not run.