perf(attn): grid-target KV-split cap for int8-MMA long-context decode#345
Draft
fansilas wants to merge 1 commit into
Draft
perf(attn): grid-target KV-split cap for int8-MMA long-context decode#345fansilas wants to merge 1 commit into
fansilas wants to merge 1 commit into
Conversation
… (+11.5% 32k, +8.1% 16k)
Member
⚪ sparkinfer auto-eval —
|
| metric | value |
|---|---|
| label | eval:none |
| Qwen3.5 score | eval-qwen35:none (pass) |
| Qwen3.6 score | eval-qwen36:none (pass) |
| Qwen3.5 vs same-box main | 282.88 tok/s → +0.6% (+1.8) |
| Qwen3.5 scored decode (128 ctx · 128-context) | 284.66 tok/s |
| Qwen3.5 correctness | top-1 96.8% · KL 0.0195 |
| Qwen3.5 128-token no-regression gate | 284.66 tok/s vs main 282.88 tok/s · pass |
| Qwen3.5 512-context no-regression gate | 281.53 tok/s vs main 280.04 tok/s · pass |
| Qwen3.5 4k-context no-regression gate | 272.64 tok/s vs main 271.88 tok/s · pass |
| Qwen3.6 vs same-box main | 427.46 tok/s → -0.5% (-2.2) |
| Qwen3.6 scored decode (128 ctx · 128-context) | 425.22 tok/s |
| Qwen3.6 correctness | top-1 96.1% · KL 0.0174 |
| Qwen3.6 128-token no-regression gate | 425.22 tok/s vs main 427.46 tok/s · pass |
| Qwen3.6 512-context no-regression gate | 420.41 tok/s vs main 422.8 tok/s · pass |
| Qwen3.6 4k-context no-regression gate | 403.36 tok/s vs main 405.75 tok/s · pass |
| Qwen3.6 16k-context no-regression gate | 379.27 tok/s vs main 381.9 tok/s · pass |
| Qwen3.6 32k-context no-regression gate | 351.92 tok/s vs main 354.31 tok/s · pass |
| Qwen3.5 optimize | eval:none · 284.66 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B guard accuracy | top-1 96.1% · KL 0.0174 · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 128 | 425.17 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 512 | 420.35 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 4k | 403.29 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 16k | 379.78 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 32k | 352.01 tok/s · pass |
| Qwen3.6 optimize | eval:none · 425.22 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) guard accuracy | top-1 96.8% · KL 0.0195 · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 128 | 284.36 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 512 | 281.0 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 4k | 272.81 tok/s · pass |
Within the significance gate — no verified speedup over same-box main.
RTX 5090 (sm_120) · 128/512/4k/16k/32k guarded · scored vs same-box main · strongest context scores · built from source · correctness vs llama.cpp. Automated — not merged; merge manually after review.
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.
Summary
One decode scheduling fix for the int8 tensor-core flash-decode at long context, output-neutral to main (only the KV-work partition changes).
Grid-target n_splits cap. The depth-adaptive KV-split count jumps to 256 at >8k context — a value tuned for the older bf16 tile kernel. For the int8-MMA flash-decode (
fa_split_gqa_mma_i8_kernel, 5 CTAs/SM), 256 over-splits: thenum_kv_heads*256grid spills a partial 2nd occupancy wave (tail), and the per-split chunk shrinks until the QK warps idle (gblk<8). On an nsys node trace the split kernel is ~27% of the 32k-context token and already runs at ~89% of memory bandwidth — so the win is the schedule, not the kernel.This caps
n_splitsto a grid that fills ~3/4 of one occupancy wave:(num_sms*5*3/4)/num_kv_heads. The optimal grid is independent of seqlen — on the RTX 5090 (170 SMs) both 16k and 32k decode peak at grid ~640 (n_splits 159 at 4 KV heads). The cap only bites for higher KV-head counts: hd128 Qwen3-MoE (4 KV) -> 159; hd256 (2 KV -> cap 318, above the 256 tier) and short context (<8k, n_splits 32/128) are unchanged. The online-softmax combine is exact for any split count, so this is correctness-neutral.A/B toggle:
SPARKINFER_NSPLITS=256restores the pre-cap fixed split count for the comparison below.Proof of speedup
sm_120)Decode tok/s (end-to-end,
bench/scripts/bench.sh,Qwen3-30B-A3B-Q4_K_M.gguf, 128 decode tokens):Same-box A/B, both built on current main (v0.4.0), 2 reps each:
128 / 512 / 4k are unchanged — the cap does not engage below 8k (int8 KV + the MMA path start at ctx>=8192). Correctness: the split count is a KV-work partition; the log-sum-exp combine is exact for any n_splits (main already ships 128 at 4k, 256 at 16k), so the attention output is unchanged up to float reduction order.
Relation to open PRs
The n_splits grid-target cap is original — no open PR does it. The only file touched is
runtime/src/models/qwen35.cpp, shared with several open PRs (#329, #308, #294, #285, #283, #272, #267), but the change is a small self-contained addition to the depth-adaptive split block. Added-line containment against every one of those (and every merged/closed PR on this file) is <=14.3% — a single shared}. No kernel changes.