Repository navigation
feat(attention): FlyDSL paged decode for MiniMax-M3 on gfx1250 - #2710
Conversation
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
be939fe to
93ff6fd
Compare
gfx1250 has no gluon paged decode, so MiniMax-M3 dense and sparse decode had no paged kernel there. Route them to FlyDSL's pa_decode, which supports gfx1250 with BF16 and per-token FP8 KV. - ATOM_PA_FLYDSL=1 opts in, as on gfx942/gfx950. gfx1250 needs it: a call left for gluon there raises with a pointer to the flag. BF16 KV goes to FlyDSL only where gluon is absent. - Dense decode on gfx1250 takes the unified arm, which hands FlyDSL every call it accepts and passes the SHUFFLE V cache as its 5D view (FlyDSL reads a 4D V as the plain layout). - Sparse rows on gfx1250 skip pa_fwd_asm, which has no code objects there. - On gfx1250, a plan past 4096 sequences sets max_batch_size (aiter #6462), up to what one block's LDS holds (81792), so a sparse prefill step stays on FlyDSL. gfx942/gfx950, and an aiter without max_batch_size, keep 4096. - Arch checks use get_gfx_runtime(), which ignores GPU_ARCHS. - ATOM_USE_UNIFIED_ATTN keeps gfx1250 dense decode on unified_attention. - The explicit-plan API probe imports aiter.ops.flydsl.pa_decode by module path: the package lazily exports a pa_decode function of the same name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The separate Gemma norm + RoPE + cache path, taken above ATOM_QK_NORM_ROPE_CACHE_FUSION_MAX_TOKENS, always called reshape_and_cache_with_pertoken_quant. A BF16 KV cache has no dequant scales, so long prefills could not be written. Use reshape_and_cache for non-FP8 caches; the FP8 path is unchanged.
93ff6fd to
f98f70c
Compare
|
|
||
|
|
||
| @functools.cache | ||
| def gluon_decode_supports_arch() -> bool: |
There was a problem hiding this comment.
put these into aiter, instead of ATOM
There was a problem hiding this comment.
Moved the backend capability checks into aiter in ROCm/aiter#7026. Once that API is available, this PR can import the two helpers and drop the local architecture table.
There was a problem hiding this comment.
Updated in 8a6f9c1: ATOM now imports both capability queries from their owning aiter backends and removes the local architecture table/helpers. ROCm/aiter#7026 has merged.
There was a problem hiding this comment.
Refined in e753771: each consumer now imports the exact capability helper directly from its owning aiter module; there is no ATOM alias/re-export layer.
Co-authored-by: Cursor <cursoragent@cursor.com>
8a6f9c1 to
e753771
Compare
|
Thanks for moving the capability checks into aiter. I re-read at c0354d4 by reading the source, checking against aiter Must fix1. On gfx1250, every new sparse-prefill length compiles a planner and leaves a buffer set that is never freed (
This PR makes sparse rows skip Prefill plans need a bounded set of shapes: size the plan by a capacity bucket and reuse its scratch, or scope the plan and scratch to the step, instead of caching one per row count. Should fix2. On gfx1250 an unsupported call raises mid-serve instead of being refused at startup ( 3. The error for FP8 dense decode without 4. The kernel choice is now made in two places ( 5. The docs and docstrings describe a fallback that gfx1250 does not have. Smaller
|
…ll plan precondition Sparse prefill plan reuse, and keeping decode and prefill plans apart, landed with #2710 (plan_step_owner / plan_cache_owner). What remains: - run_pa_decode takes exp_sums / max_logits / temporary_output optionally and the four callers (M3 sparse, native dense, vLLM MHA, SGLang) omit them: pa_decode_gluon sizes and allocates its own from the query, so a FlyDSL call allocates three unused buffers per layer no more and no caller keeps a copy of the kernel's scratch shapes. - The prefill wrapper's docstring states when plan_step_owner may be passed. - Tests: the omitted-scratch path outside the FlyDSL-gated classes, and an AST check that no run_pa_decode caller passes scratch.
…ll plan precondition (#2761) Sparse prefill plan reuse, and keeping decode and prefill plans apart, landed with #2710 (plan_step_owner / plan_cache_owner). What remains: - run_pa_decode takes exp_sums / max_logits / temporary_output optionally and the four callers (M3 sparse, native dense, vLLM MHA, SGLang) omit them: pa_decode_gluon sizes and allocates its own from the query, so a FlyDSL call allocates three unused buffers per layer no more and no caller keeps a copy of the kernel's scratch shapes. - The prefill wrapper's docstring states when plan_step_owner may be passed. - Tests: the omitted-scratch path outside the FlyDSL-gated classes, and an AST check that no run_pa_decode caller passes scratch.
Changes
Run MiniMax-M3 paged decode on gfx1250 (MI455) through FlyDSL. gfx942/gfx950 are unchanged.
ATOM_PA_FLYDSL=1routes dense and sparse paged decode to FlyDSL, as on gfx942/gfx950, for FP8 and BF16 KV. gfx1250 needs it, since it has no gluon decode.max_batch_size, so large sparse prefill steps stay on FlyDSL. gfx942/gfx950 keep the 4096 cap.pa_fwd_asmon gfx1250.ATOM_QK_NORM_ROPE_CACHE_FUSION_MAX_TOKENSwrite a BF16 KV cache without per-token quantization; before, long BF16 prefills crashed (from @XiaobingSuper, fix(attention): run MiniMax-M3 on gfx1250 (unified decode, BF16 KV long prefill) #2594).This PR does not depend on ROCm/aiter#6699 to merge. The end-to-end results below use it: it fixes fused all-reduce + RMSNorm on gfx1250, which is outside this PR. Without it, MiniMax-M3 TP4 on gfx1250 loses GSM8K accuracy (0.9219 vs 0.9325 on an older aiter), and on current aiter main the server can crash during CUDA graph capture.
Test Result
MiniMax-M3-MXFP4, TP4, MI455, aiter with ROCm/aiter#6699,
ATOM_PA_FLYDSL=1. GSM8K 5-shot, full set.8K in / 1K out, concurrency 4, mean of two runs per KV dtype:
Unit tests: 168 passed.