Retune MoE token-count kernel block size for decode shapes - #6334
Draft
shanmugamr1992 wants to merge 1 commit into
Draft
Retune MoE token-count kernel block size for decode shapes#6334shanmugamr1992 wants to merge 1 commit into
shanmugamr1992 wants to merge 1 commit into
Conversation
The persistent token-count kernel used BLOCK_SIZE=1024, which makes each thread issue eight atomics back to back rather than spreading them across CTAs. At decode shape the kernel is flat in both grid size and routed-pair count, the signature of per-thread serialization rather than launch geometry or atomic volume. Sizing the block to 128 cuts the kernel from 8.08 us to 2.11 us; larger blocks only pay off once there are enough pairs to fill the machine, where the curve is flat. Measured on GB200, Qwen3-30B-A3B EP4/TP1, BS256: +2.29% decode throughput. Bit-exact. Kill switch: MCORE_COUNT_TOKENS_BLOCK. Signed-off-by: shanmugamr1992 <shanmugamr1992@gmail.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
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 changed and why
_count_local_tokens_kernel_persistent(inference MoE dispatch) hardcodedBLOCK_SIZE = 1024. Triton launches it with 128 threads, so each thread owns 8(token, topk)pairs and issues itstl.atomic_addincrements serially. Atdecode shapes that makes the kernel cost far more than its work: 7.95 µs per
launch to count 256 tokens over 32 local experts, i.e. 381.8 µs per decode
step across 48 layers.
The mechanism is per-thread serialisation, not launch geometry or atomic volume.
Measured on GB200, three hypotheses separated with a CUDA-graph-replay harness:
BLOCK_SIZEThe kernel is flat in grid and flat in routed pairs (12.31 / 12.30 / 12.29 µs at
2048, 8192, 32768 pairs), which is the signature of a fixed per-thread cost rather
than a throughput limit. Atomics do dominate — removing them takes 4.51 → 1.56 µs —
but the fix is to spread them across CTAs, not to issue fewer.
BLOCK_SIZE=128is the right point on the curve, not the minimum: it is 3.83× fasterat the decode shape and within 1.3% of the best value at the largest graph bucket,
where
BLOCK_SIZE=64starts to lose badly.Measured gain
+2.290% throughput, 23016.42 → 23543.46 tok/s, against the mcore EP4/TP1
baseline at
af734982d. TPOT 11.1225 → 10.8735 ms (−0.2490 ms/step); averagelatency 11121.5 → 10866.6 ms.
Protocol
1× OCI GB200 node (4 GPU), Qwen3-30B-A3B, EP4/TP1,
--transformer-impl inference_optimized, NVLS dispatcher, vLLM grouped-GEMM backend. gsm8k, batch 256,OSL 1024,
num_input_tokens_avg = 60.86, 2 warmup + 5 timed iterations per arm.Arms ran back to back in the same allocation as OFF/ON/OFF/ON, each with its own
server launch.
Arm separation:
min(ON) = 23510.6 > max(OFF) = 23050.6— every ON iterationbeats every OFF iteration, with a 460 tok/s margin. Pooled sd is 18.0 (OFF) and 23.2
(ON) tok/s, so the win is ~23× the run-to-run noise of this configuration.
Where the time went
Attributed to
_count_local_tokens_kernel_persistent, 48 launches/step (one perlayer), in the validated steady-state decode window of the Nsight Systems trace
(125 consecutive passes, 10272.19 µs/step). Launch count is unchanged, so this is a
pure GPU-busy win with no change to scheduling idle.
Predicted 381.8 → 99.7 µs/step (−282 µs). Measured TPOT fell 249 µs/step, a 0.88
predicted-to-e2e conversion. The projection held because the microbenchmark was
validated against the trace first: it reads the shipped configuration at 8.08 µs
against the trace's 7.95 µs, a 1.6% match.
Correctness
Bit-exact. The kernel is an integer reduction via
atomic_add, so block sizechanges only which thread issues which increment, never the multiset of increments;
integer addition is associative and commutative.
BLOCK_SIZE=1024in 2280/2280 cases: 10 seeds × 3 buffercapacities {16384, 4096, 512} × 7 valid-token counts {0, 1, 7, 63, 256, 1000, 4096}
× 4 local-expert offsets {0, 32, 64, 96} × blocks {128, 256, 512}.
completions in both arms.
Kill switch
MCORE_COUNT_TOKENS_BLOCK=1024restores the previous behaviour.Scope and risks
topk=8, 32 localexperts. The block-size curve depends on threads per program and on experts per
rank, so a very different expert count may prefer another point.
BLOCK = 1024, because its grid isceil_div(max_pairs, BLOCK)and shrinking theblock would change its launch geometry too — an unmeasured change.
Artifacts
skills/run-qwen-model/EXPERIMENTS.md,GATE G4/EXP-02…/agents-space/runs/exp02-count-block-20260806-145539…/runs/exp01-nsys2-124241/mcore_exp01.{nsys-rep,sqlite}