tune(ep/v2): give fp8 dispatch its own gfx1250 EP4 row - #598
Open
jhchouuu wants to merge 1 commit into
Open
Conversation
The gfx1250 (4, 7168, 6) dispatch entry has one row keyed None, so fp8 has been running bf16's geometry. Two things make that the wrong answer for fp8. THE ROUND RULE reaches further down than the None row's first edge admits. topk 6 on wave32 gives _tpi = 1 (32 % 6 != 0), so one round is block*warp tokens and the ~39us rendezvous floor is held as soon as total warps >= ct. Blocks past that are idle: at 64 tokens, 4 blocks hold the floor that 64 blocks hold. The None row spends 64 blocks everywhere below 512 because that is what bf16 wants, not because the tokens need them. fp8 also shows no per-block warp penalty where bf16 does -- bf16 64x16 runs 3-4us behind 64x8 at every small ct, while fp8 measures the same either way. So fp8 can take 16 warps/block and cover a round with half the blocks. bf16 cannot, which is why it keeps the None row untouched. ct 4x16 8x16 16x16 32x16 | 64x8 64x16 128x16 64 39.1 39.4 39.3 39.4 | 39.1 38.9 128 50.7 39.4 39.1 39.5 | 39.1 39.5 256 77.1 50.8 39.7 40.0 | 39.3 39.2 512 124.1 76.9 51.5 40.7 | 40.7 40.8 1024 | 53.0 43.8 2048 | 61.0 57.9 4096 | 96.6 87.7 Two kinds of gain, and they are not the same kind. Below 1024 the latency is unchanged (+0.0 to +1.0% against the shipped row) and what the smaller grid buys is CUs for whatever overlaps dispatch -- 4/64 of the blocks at 64 tokens, 8/64 at 128, 16/64 at 256, 32/64 at 512. That is the trade the combine table above already makes for itself. At 2048 and 4096 it is plain latency: the None row holds 64x16 to 4096, but 128x16 is ahead from 2048 on, worth +4.1% and +9.3% end to end. Measured on 4x gfx1250, EP4, hidden 7168, topk 6, 384 experts, fp8 dispatch with bf16 combine, cuda graph, through tests/.../bench_ep.py, which gates every point on its identity-expert check. Small tiers are the mean of 3 routing draws at 600 iterations; the 2048/4096 figures are an unpinned A/B of this table against the shipped one, interleaved, 2 reps. The box was health-checked against the canary this file documents (bf16 4096/64x16 read 144.6us, under the ~157us healthy mark). Only (4, 7168, 6) is measured. topk 8 keeps its own row: 32 % 8 == 0 puts _tpi at 4, so a round covers four times the tokens and every edge moves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
The gfx1250
(4, 7168, 6)dispatch entry has a single row keyedNone, so fp8 has been running bf16's geometry. Two things make that the wrong answer for fp8.The round rule reaches further down than the
Nonerow's first edge admits_tpi = 1at topk 6 on wave32 (32 % 6 != 0,ep_intranode_1250x.hpp:279), so one round isblock*warptokens and the ~39 us rendezvous floor is held the moment total warps ≥ ct. Blocks past that are idle — at 64 tokens, 4 blocks hold the floor that 64 blocks hold. TheNonerow spends 64 blocks everywhere below 512 because that is what bf16 wants, not because the tokens need them.Coming up short of a round is a cliff, not a slope, which is the rule showing its edge:
4x16is +30% at ct=128 and +96% at ct=256.fp8 has no per-block warp penalty; bf16 does
bf16
64x16runs 3-4 us behind64x8at every small ct, while fp8 measures the same either way. So fp8 can take 16 warps/block and cover a round with half the blocks. bf16 cannot — which is why this PR leaves theNonerow completely untouched.What it buys — two different kinds of gain
Unpinned A/B of this table against the shipped one, interleaved, 2 reps, every point through
bench_ep.py's identity-expert gate:Below 1024 the latency does not move; what the smaller grid buys is CUs for whatever overlaps dispatch — the same trade the combine table makes for itself in #577. At 2048 and 4096 it is plain latency: the
Nonerow holds64x16out to 4096, but128x16is ahead from 2048 on.Provenance
4× gfx1250, EP4, hidden 7168, topk 6, 384 experts, fp8 dispatch + bf16 combine, cuda graph, driven through
tests/python/ops/dispatch_combine_v2/bench_ep.py. Small tiers are the mean of 3 routing draws at 600 iterations; 2048/4096 come from the unpinned A/B above.The box was health-checked against the canary this file documents — bf16 4096/64x16 read 144.6 us, under the ~157 us healthy mark.
Measurements were taken at
63099a17. #577 has landed since and reworked the combine barrier, butEpDispatch1250xBodyis byte-identical between that commit and currentmain, so the dispatch numbers carry over unchanged. The merged schedule was re-checked against #577's new combine buckets: fp8 picks up the new combine geometry at the union of edges, and the bf16 / fp4 dispatch columns are unchanged.Scope
Only
(4, 7168, 6)is measured. topk 8 keeps its own row on purpose:32 % 8 == 0puts_tpiat 4, so a round covers four times the tokens and every edge moves — it needs its own sweep.experts_per_rankstays a wildcard, as in the existing entry (only 96 was measured).🤖 Generated with Claude Code