Repository navigation
Conversation
#2725 passes the pass's real row count (num_local_tokens) to aiter fused_moe on every Mxfp4MoEMethod call. aiter cannot honour that count in its inline-sort kernels, so it drops the whole tuned row and falls back to default heuristics. Kimi-K3's tuned rows for M <= 64 (E=896, decode) are all inline-sort, so its decode MoE got 35-45% slower. Routing already sends rows past the real count to expert -1, so the count is only needed for a prefilled shared column. Pass it only there. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
| # Routing already sends rows past the real count to expert -1; | ||
| # only a prefilled shared column still needs the count. Passing | ||
| # it otherwise makes aiter discard its tuned inline-sort rows. | ||
| num_local_tokens=( |
There was a problem hiding this comment.
should fixed by moe side, instead of here
There was a problem hiding this comment.
agree. Just confirm, do you mean fix in somewhere else in ATOM or fix in AITER kernel side?
There was a problem hiding this comment.
Fixed on the aiter side instead: ROCm/aiter#7020 — the inline-sort sort skips ids outside [0, E), the BM16 sort honours num_local_tokens on device (CUDA-graph safe), and fused_moe no longer discards the tuned inline-sort row when the count is passed. With it, K3's decode MoE with the count matches the no-count timing (M=1..64 within 1%, was +29-75%), no ATOM change needed.
Converting this PR to draft; I'll close it once aiter#7020 lands.
|
Superseded by ROCm/aiter#7020 (merged as f2d9434bbc): the MXFP4 inline-sort path now accepts num_local_tokens and skips -1 ids, so ATOM keeps passing the count and K3 keeps its tuned rows. Closing as promised. |
Summary
#2725 started passing the pass's real row count to aiter
fused_moe(num_local_tokens=scheduled_tokens_gpu) on everyMxfp4MoEMethod.applycall. aiter's inline-sort MXFP4 kernels cannot take that argument. aiter therefore drops the whole tuned row and falls back to default heuristics:_mxfp4_inline_sort_unsupportedinaiter/fused_moe.py. It is present in both the old and the new aiter, so only the ATOM caller changed.kimik3_a4w4_tuned_fmoe.csv, gfx950, E=896, topk=16) are all inline-sort, e.g.flydsl_mxmoe_g1_a4w4_16x256x256_f16in_nt_situv2_xcd4+flydsl_moe2_..._sbm16.flydsl_mxmoe_g1_a4w4_64x256x256_situv2/..._t64x256x128_reduce_sbm64, and the routed MoE gets 35–45% slower for every decode batch of 4–64 rows.Fix: routing already sends rows at or past the real count to expert -1 (
select_experts→num_valid_rows). The count is therefore only needed for a prefilled fused shared-expert column, which routing cannot mask. This PR passesnum_local_tokensonly whenlayer.num_fused_shared_experts > 0. Layers without a fused shared column go back to the pre-#2725 call and keep their tuned rows.Impact observed
Kimi-K3 TP8 MXFP4 on MI355X, AgentX benchmark (InferenceX), image
nightly_202610261558(ATOM e893780) vs the 10-19 image:Local reproduction on one MI355X node, same recipe. The old ATOM is f08cd7f + aiter 7be01d1c7; the new is the stock
nightly_202610261558:The new C16 run has a larger KV pool (14179 vs 13259 blocks), so the slowdown is not KV-pool driven.
The C4 server log on the new image has ~60k of the warning above. The old image has 0.
We ruled out the other candidates:
Unit-level A/B (aiter
fused_moe, K3 TP8 shape)The benchmark times one aiter
fused_moecall:per_1x32fp4x2 a4w4, preshuffled weights.biased_grouped_topk, withAITER_FLYDSL_USE_HERD=1 AITER_FLYDSL_HERD_MIN_M=64as in the recipe. The ids match a torch reference.AITER_SITUV2_A4W4=1 AITER_FLYDSL_STAGE2_FP8=1.nlt=Noneis this PR's and the pre-feat(moe): route before the rows move; per-pass real row counts; V4.1 FP8 KV #2725 behaviour.nlt=tensoris the current main behaviour.nlt=None (µs)
nlt=tensor (µs)
nlt=None (µs)
nlt=tensor (µs)
_f16in) and the fallback an fp4 one. This is expected; it is not a correctness bug.benchmark script
Tests
tests/test_mega_mxfp4_method.py::test_real_row_count_only_reaches_fused_moe_for_a_shared_column. With no fused shared column the count is not forwarded; with one it is. It fails on main and passes with this change.tests/test_mega_mxfp4_method.py,tests/test_pass_scheduled_tokens.py,tests/model_ops/test_dp_gather_routed_rows.py,tests/model_ops/test_shared_expert_dispatch.py(40 passed).Not done yet (draft)
Scope: only the
Mxfp4MoEMethodFlyDSL tail. The other twonum_local_tokenscall sites (UnquantizedFusedMoEMethod,Iq2rMoEMethod) are untouched: they are not MXFP4 a4w4, so the inline-sort rows never apply to them.cc @valarLip (author of #2725)
This PR was prepared with AI assistance (Claude Code): root-cause analysis, the fix, the test, and the benchmark. All results were run and reviewed by the author.
🤖 Generated with Claude Code