Skip to content

Performance: decode overlap, GQA-shared split attention, short-prompt GEMM tile (1.0.3) - #3

Merged
jkyberneees merged 5 commits into
mainfrom
perf/decode-overlap-attn-split-short-prefill
Oct 31, 2026
Merged

jkyberneees merged 5 commits into
mainfrom
perf/decode-overlap-attn-split-short-prefill

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Changes

  • Decode encode overlap (Transformer.swift): while the GPU runs token N, the CPU encodes the command buffer for token N+1. Encoding depends only on (T, offset), and token ids are read from ids at execution, so the buffer is used only on an exact (T=1, offset) match and dropped otherwise.
  • Split decode attention for context ≥ 256 (attention_split + attention_combine): each K/V row is read once per GQA group instead of once per query head. Partials are merged in the original order. The K/V prefetch (AU) stays at 1 because it measured no faster. New test splitDecodeAttentionIsBitIdentical.
  • Short-prompt GEMM tile (qgemms): T = 5–16 uses an 8- or 16-token tile instead of padding to 32. The accumulation order is the same as qgemm. Kernel tests cover T = 8, 9, 15, 16, 17.
  • Version 1.0.3, CHANGELOG, README performance table.

Measurements (M2 Pro, 1.0.2 vs this branch, 4 alternating pairs, run-to-run spread ≤ 0.5%)

Qwen3 0.6B Llama 3.2 1B Mistral 7B
Decode @16 +2.8% +0.8% +0.5%
Decode @1k +6.7% +3.8% +2.2%
5-token prompt −42% −50% −50%
15-token prompt −27% −32% −30%
Prefill 512 / 2048 flat flat flat

Split threshold check (split off vs on, same binary): @256 +0.3% / +1.0%, @512 +0.5% / +2.9% (Mistral / Qwen3), so 256 causes no regression.

Correctness

  • swift test: 95 tests pass.
  • Greedy output is token-identical to 1.0.2 on Qwen3 0.6B, Qwen2.5 0.5B, Llama 3.2 1B, Phi-3.5 and Mistral 7B, with long prompts and with 12–13-token prompts that take the new short-prompt path.

Rejected during the pass: a small-matrix matvec variant (qmv4r), which made Qwen3 0.6B decode 5% slower.

🤖 Generated with Claude Code

jkyberneees and others added 5 commits October 31, 2026 17:14
…current one

Encoding a forward pass depends only on (T, offset, computeLogits, allLogits); token ids are
read from the ids buffer at execution time. After committing a final step, step() encodes the
T=1 pass for offset+T before waiting, and commits it on the next call only on an exact match
(otherwise it is dropped uncommitted). Same kernels, same dispatch order: outputs unchanged.
The embedding lookup pipeline is resolved once at init instead of by name every step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dding to 32

qgemm tiles 32 tokens, so a 5..15-token prefill paid the MMA work of 32
tokens (Mistral 7B: ~14.4 GFLOP/token x 32 / 2.45 TFLOPS = ~190 ms, the flat
~200 ms measured for T=5..15). qgemms uses a BM = 8 or 16 token tile with 4
simdgroups x 8 output columns, K-step 64 and register prefetch of the next
step. Per output element the arithmetic is the same as qgemm (fp32 s*q+b
dequant, zero-padded x, 8x8x8 MMAs with k ascending, 8-aligned tiles), so
the accumulation order is unchanged. T=1, T=2..4 and T>=17 paths untouched.
Kernel tests cover T = 8, 9, 15, 16, 17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ernel shares K/V across GQA heads

attention<E,ANSG> now loads K/V rows for 4 keys up front (clamped to L-1) and
processes them in the original order, so more reads are in flight.

For decode at context >= MLXR_ATTN_SPLIT_MIN (default 256), attention_split runs
nKV x 8 threadgroups of 4 simdgroups; each simdgroup covers all query heads of
its GQA group, so each K/V row is read once per group instead of once per head.
It writes the same 32 per-simdgroup partials the fused kernel keeps in
threadgroup memory, and attention_combine merges them in the same order: the
arithmetic is unchanged and logits are bit-identical (new test
splitDecodeAttentionIsBitIdentical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter at short context

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Failed ❌

View logs ↗
38e984d 2026-10-31T16:46:09.774Z View logs ↗

@jkyberneees
jkyberneees merged commit ae22b84 into main Oct 31, 2026
4 of 5 checks passed
@jkyberneees
jkyberneees deleted the perf/decode-overlap-attn-split-short-prefill branch October 31, 2026 16:49
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.

1 participant