Skip to content

perf(decode): occupancy-first adaptive n_splits — 64-split mid-context plateau (skip 128)#134

Open
milosde111 wants to merge 1 commit into
gittensor-ai-lab:mainfrom
milosde111:perf/adaptive-nsplits-occupancy
Open

perf(decode): occupancy-first adaptive n_splits — 64-split mid-context plateau (skip 128)#134
milosde111 wants to merge 1 commit into
gittensor-ai-lab:mainfrom
milosde111:perf/adaptive-nsplits-occupancy

Conversation

@milosde111

@milosde111 milosde111 commented Jul 2, 2026

Copy link
Copy Markdown

Summary

Replaces the mid-context n_splits step in the Qwen3-30B-A3B adaptive flash-decode schedule (runtime/src/models/qwen35.cpp). After #138, main jumps to 128 splits past 512 tokens; this PR uses a 64-split plateau through 6144 tokens, then MAX_NSPLITS=256.

The flash-decode grid is num_kv_heads · n_splits CTAs (num_kv=4 → 128 CTAs at 32 splits). At bs=1 the split kernel is occupancy-bound (~300 GB/s) while LM-head/MoE GEMVs already sit at 93–95% of the ~1.79 TB/s roofline — so more splits help until combine/partials cost dominates. Micro-bench on the split+combine path shows 128 is never optimal in isolation; the sweet spot is 32 (short) → 64 (mid) → 256 (long).

seqlen n_splits
≤ 2·split_chunk (≤512) 32
≤ 24·split_chunk (≤6144) 64
else 256

Kernel files untouched — launch heuristic only. Gated by SPARKINFER_NSPLITS pin and SPARKINFER_SPLIT_CHUNK. n_splits only repartitions the KV reduction; online-softmax combine is exact → accuracy gate unaffected. Monotonic in seqlen → at most two CUDA-graph re-captures per generation.

Proof of speedup

  • Tested on RTX 5090 (sm_120)

Decode tok/s (end-to-end, from bench/scripts/bench.sh):

decode tok/s
before (main) 394.23
after (this PR) 350.33

(scored at ctx=4096 — see full sweep below)

RTX 5090, sm_120, 2026-07-03
NVIDIA GeForce RTX 5090, compute capability 12.0
Qwen3-30B-A3B Q4_K_M, n=128 decode tokens, bs=1

=== main (before: 32 → 128 → 256) ===
ctx=128   decode tg: 490.07 tok/s
ctx=512   decode tg: 471.64 tok/s
ctx=2048  decode tg: 427.78 tok/s
ctx=4096  decode tg: 394.23 tok/s
ctx=8192  decode tg: 332.54 tok/s
ctx=16384 decode tg: 270.82 tok/s

=== perf/adaptive-nsplits-occupancy (after: 32 → 64 → 256) ===
ctx=128   decode tg: 484.42 tok/s
ctx=512   decode tg: 463.38 tok/s
ctx=2048  decode tg: 425.64 tok/s
ctx=4096  decode tg: 350.33 tok/s
ctx=8192  decode tg: 335.81 tok/s
ctx=16384 decode tg: 269.23 tok/s

@ai-hpc ai-hpc added area:runtime subsystem (emission weight 0.26) not-tested Awaiting maintainer approval to run on RTX 5090; not evaluated labels Jul 3, 2026
@milosde111 milosde111 force-pushed the perf/adaptive-nsplits-occupancy branch from c37787f to 9275b3d Compare July 3, 2026 03:36
@ai-hpc ai-hpc added needs-benchmark Box ticked but decode before/after not filled with a real improvement — not evaluated and removed not-tested Awaiting maintainer approval to run on RTX 5090; not evaluated labels Jul 3, 2026
@ai-hpc

ai-hpc commented Jul 3, 2026

Copy link
Copy Markdown
Member

⏳ Needs a benchmark to be evaluated

You ticked Tested on RTX 5090 but the decode before → after tok/s table is still empty / placeholder (or shows no gain). The on-device eval won't run until it shows a real improvement.

Fill it from the end-to-end decode bench (not an isolated-kernel microbench):

bench/scripts/bench.sh --download            # baseline (before)
bench/scripts/bench.sh --download            # your branch (after)

Then the bot greenlights it on the next poll and evaluates it on an RTX 5090.

@milosde111 milosde111 changed the title perf(decode): occupancy-first adaptive n_splits for flash-decode attention (1.2–1.4× split kernel, 0.75k–16k ctx) perf(decode): occupancy-first adaptive n_splits — 64-split mid-context plateau (skip 128) Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:runtime subsystem (emission weight 0.26) needs-benchmark Box ticked but decode before/after not filled with a real improvement — not evaluated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants