Repository navigation
Conversation
5fee525 to
0dcad1e
Compare
…el for chunked prefill (ROCm#3606) * fix(mla): always write partial output + LSE for prefill PS tiles The PS scheduler in v1_2_host.cuh's generate_work_info tagged tiles that a single threadgroup could absorb from block 0 with the sentinel partial_o_loc = -1, causing generate_reduce_info to exclude them from reduce_indptr / reduce_final_map / reduce_partial_map. As a result mla_reduce_v1 never wrote final_lse[qo_start:qo_end, :] for those tiles, leaving stale workspace bytes that downstream consumers (vLLM's chunked-context MLA prefill on MI350) read as garbage LSE and fed into merge_attn_states, causing a ~2-3pp gsm8k accuracy regression on DeepSeek-V3. Always assign a real partial_o_loc so every tile produces a partial output + partial LSE that reduce processes (num_partials==1 for what used to be the fast-path tiles). The kernel already supports this path -- only the host scheduler needed changing; no assembly edits. The if(work.partial_o_loc == -1) continue; guard in generate_reduce_info is left in as defensive coding. Mirrors PR ROCm#3542 ("[Triton-Gluon-MLA-GFX950] return_lse: full decode + merged fp32 lse"), which fixed the analogous bug in the triton-gluon decode kernel's NUM_KV_SPLITS==1 fast path. * fix: dont skip reduction of tiles with num_split==1 Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: increase max_partial now that we support split tiles Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: compute the work and partial based on actual kv size Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: return final_lse instead of partial attn_lse from kernel wrapper Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * test: add proper final lse validation test Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * test: add non-causal chunk context to correctness test Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * pass max_kvlen to correctness test Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: simplify comments Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: remove redundant comment Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: remove redundant handling of partial_o_loc=-1 Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: simplify comment Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: indent Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: indentation Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: avoid running reduce when num_splits==0 Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: add comment about fullgraphs Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: size without mxa kvlen Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: fix docstring Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: rename lse_ref in test Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: add need_lse flag This avoid avoid unnecessary reduction when lse is not needed. Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: simplify comments Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: comment in get_ps_metadata_info_v1 Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: restructure to minimzie diff Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: use qo_len in test when available instead of ctx_len Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: remove empty eol spaces Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: set max_partials to one per qo-tile + splits Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: set lower lse test tolerances Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: typo Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: set lse error atol to 3e-2 to be above the fp8 rounding onise Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: fix black erro Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: fill final_lse buffer with -inf (#3) Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: remove redundant asserts (#6) Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: include cassert in v1_2_host.cuh (#7) Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: add return_lse param and check that ensures final_lse is populated completely if return_lse (#3 & #4) Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: align flydsl reduce kernel with the cu variant Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * chore: indent py bindings Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: convert asserts to AITER_CHECK Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: address comments about tests Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: add test cases to flydsl reduce to ensre parity Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: switch to int64 slot offsets Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: add test of aiter.mla.mla_prefill_ps_fwd python wrapper Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> --------- Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com>
Clean replay of the fast-scan tuning fix from PR #3 onto current upstream main, excluding the unmerged worker-policy fan-out. - gemm_moe_tune: accuracy-aware fast scan for the FlyDSL mxfp4 a4w4 tuner (--fast-scan): deduplicated parallel precompile, shared fixture/reference tensors, device-side cosine reduction, coarse scan -> latency finalists -> accuracy promotion -> ordered backfill, plus finalist summary. Non-mxfp4 tuners reject --fast-scan. - aot/flydsl: optional start_method for the file pool; batch compile helpers in mxfp4_moe. - mp_tuner: skip the 3s pid stagger when mp_num == 1. - test_common: configurable profile_warm_iters for perftest. - gen_instances: add GLM-5.3 / GLM-5.3-Flash / Qwen3-Coder-Next / Inkling / MiMo-V2.5-Pro shapes. - Add glm53 fp4 tuned/untuned configs, fast-scan README section, and a CPU-only regression test for the scan funnel.
7440ef7 to
7e18908
Compare
Review fixes for the MXFP4 fast-scan tuning path: - build the shared per-shape torch reference with the same AITER_MXFP4_TUNE_SWIGLU_LIMIT clamp that _run_candidate applies to the per-candidate reference and to the kernel launch; without it every candidate was rejected against an unclamped reference whenever the tuning limit was set - remove the unused _rank_mxfp4_candidates timing-bucket helper (only its own test referenced it) and route the coarse finalist/backfill ordering through the tested _select_mxfp4_performance_finalists so production and tests share one ordering - align the README funnel description with the actual finalist selection - extend the CPU regression suite: shared-reference clamp propagation, kernel/reference clamp parity, and in-memory jobs_from_rows equivalence with parse_csv on the shipped GLM-5.3 tuned CSV
Review follow-ups on the MXFP4 fast scan: - Prefer the raw `_err` ratio over the rounded err1/err2 percent strings when a finalist retime merges the coarse error, so a 1.1% display string can no longer round a candidate below a slower one with a true 0.01120. - Apply AITER_MXFP4_TUNE_SWIGLU_LIMIT to the stage-1 precompile jobs, matching the runtime clamp. Without it every precompiled kernel missed the cache and the scan JITed while scoring. - Add CPU-only regression tests for both paths and register the module in the tuning test split and the level 0+1 CI suite. - Correct the README's profiler-sample and accuracy-bucket claims, and document the swiglu-limit contract.
The Checks workflow runs `black --check --diff .` (psf/black@stable, 26.10.1 today) and `ruff check .` (pinned 0.16.0) over the whole tree. main passes both; this branch regressed them. - black 26.10.1 collapses the hand-wrapped argument lists and conditions in gemm_moe_tune.py, mp_tuner.py and the new tuning test module, so the style gate failed on three files. - ruff SIM115 flagged the conditional `open()` in parse_csv: choose the path-or-stream context manager inside the `with` statement instead of binding it first, so the file stays managed there. - ruff SIM117 flagged two nested `with` blocks in the new tests; merge each pair into one multi-context `with` (identical semantics). Validated: `black --check .` and `ruff check .` are clean at this head, and op_tests.tuning_tests.test_fast_tuning still passes 24/24.
|
Added a Fast-scan arguments and usage section to the PR description, with the complete argument table, explicit tuning and production-validation commands, and measurement semantics checked against head
Warm-up clarification: the first round already compiles and exercises every surviving candidate. A finalist normally reaches retiming after 1 untimed accuracy-check invocation and 10 measured invocations. The final round intentionally adds no redundant initialization warm-up. Cache/clock conditions may evolve between rounds, but that is separate from needing to compile or initialize the candidate again. 100 final iterations is adjustable, not a correctness requirement. The description includes a 32-iteration experimental alternative without claiming it has the same validated winner retention. The current collector enables 1.5×IQR outlier filtering only above 30 measured iterations: 10 and 30 are unfiltered; 32 and 100 are filtered. The fast path does not automatically discard the first profiled sample. These settings replace the ordinary iteration/warm-up counts in fast-scan mode. The new documentation also explains accuracy checks, finalist backfill, the fixed 1% final selection band, and the distinction between candidate search-space selection and measurement budgets. Published benchmark results remain attributed to their original configuration. This update changes documentation only; no iteration defaults or kernel behavior were changed. |
|
In my private AITER fork, I already run AOT compilation and tuning automatically during model loading when a model encounters a previously unseen configuration within a supported module/kernel path. The kernel implementations are prevalidated; new configurations are compiled, tuned, and numerically checked before use. Once this PR is validated, I believe we can integrate the faster tuning flow into model loading upstream. That would make selecting and preparing kernels for new models largely automatic wherever existing kernel support applies, without requiring a separate offline tuning sweep. |
…OCm#6405) * [FlyDSL] Accelerate mxfp4 fmoe AOT tuning ~9x on gfx950 Clean replay of the fast-scan tuning fix from PR #3 onto current upstream main, excluding the unmerged worker-policy fan-out. - gemm_moe_tune: accuracy-aware fast scan for the FlyDSL mxfp4 a4w4 tuner (--fast-scan): deduplicated parallel precompile, shared fixture/reference tensors, device-side cosine reduction, coarse scan -> latency finalists -> accuracy promotion -> ordered backfill, plus finalist summary. Non-mxfp4 tuners reject --fast-scan. - aot/flydsl: optional start_method for the file pool; batch compile helpers in mxfp4_moe. - mp_tuner: skip the 3s pid stagger when mp_num == 1. - test_common: configurable profile_warm_iters for perftest. - gen_instances: add GLM-5.3 / GLM-5.3-Flash / Qwen3-Coder-Next / Inkling / MiMo-V2.5-Pro shapes. - Add glm53 fp4 tuned/untuned configs, fast-scan README section, and a CPU-only regression test for the scan funnel. * [FlyDSL] Fix fast-scan reference clamp, drop dead funnel helper Review fixes for the MXFP4 fast-scan tuning path: - build the shared per-shape torch reference with the same AITER_MXFP4_TUNE_SWIGLU_LIMIT clamp that _run_candidate applies to the per-candidate reference and to the kernel launch; without it every candidate was rejected against an unclamped reference whenever the tuning limit was set - remove the unused _rank_mxfp4_candidates timing-bucket helper (only its own test referenced it) and route the coarse finalist/backfill ordering through the tested _select_mxfp4_performance_finalists so production and tests share one ordering - align the README funnel description with the actual finalist selection - extend the CPU regression suite: shared-reference clamp propagation, kernel/reference clamp parity, and in-memory jobs_from_rows equivalence with parse_csv on the shipped GLM-5.3 tuned CSV * [FlyDSL] Keep exact funnel error and precompile the tuned swiglu clamp Review follow-ups on the MXFP4 fast scan: - Prefer the raw `_err` ratio over the rounded err1/err2 percent strings when a finalist retime merges the coarse error, so a 1.1% display string can no longer round a candidate below a slower one with a true 0.01120. - Apply AITER_MXFP4_TUNE_SWIGLU_LIMIT to the stage-1 precompile jobs, matching the runtime clamp. Without it every precompiled kernel missed the cache and the scan JITed while scoring. - Add CPU-only regression tests for both paths and register the module in the tuning test split and the level 0+1 CI suite. - Correct the README's profiler-sample and accuracy-bucket claims, and document the swiglu-limit contract. * [FlyDSL] Restore repo-wide black and ruff cleanliness The Checks workflow runs `black --check --diff .` (psf/black@stable, 26.10.1 today) and `ruff check .` (pinned 0.16.0) over the whole tree. main passes both; this branch regressed them. - black 26.10.1 collapses the hand-wrapped argument lists and conditions in gemm_moe_tune.py, mp_tuner.py and the new tuning test module, so the style gate failed on three files. - ruff SIM115 flagged the conditional `open()` in parse_csv: choose the path-or-stream context manager inside the `with` statement instead of binding it first, so the file stays managed there. - ruff SIM117 flagged two nested `with` blocks in the new tests; merge each pair into one multi-context `with` (identical semantics). Validated: `black --check .` and `ruff check .` are clean at this head, and op_tests.tuning_tests.test_fast_tuning still passes 24/24. * Fix fast tuning test paths for direct CI execution Signed-off-by: Qubitium <qubitium@modelcloud.ai> --------- Signed-off-by: Qubitium <qubitium@modelcloud.ai>
Summary
This PR makes gfx950 MXFP4 FlyDSL tuning practical for GLM-5.3-Flash TP=1. It moves cold kernel compilation out of the serial GPU candidate loop, compiles deduplicated variants in parallel, reuses one immutable shape fixture and torch reference, and applies an accuracy-aware two-stage scan.
This PR also addresses an important accuracy-selection issue: main can select a less accurate kernel for a negligible speed advantage. In the new
--fast-scanpath, final selection prefers the lowest worst observed numerical error among validated, retimed finalists within 1% of the fastest finalist. This preserves better numerical accuracy in cases where the latency difference is minor.The timing score is summed active GPU-kernel execution time for the coupled sorting + G1 + G2 operation. Python dispatch, HIP launch overhead, queue gaps, and GPU-idle gaps are excluded. The coupled port produces one measurement rather than independent stage measurements, so the CSV stores it in
us/us1;us2=0explicitly means no standalone G2 split was measured.Accuracy-selection fix: preserve accuracy when latency is nearly equal
Main uses numerical accuracy as a pass/fail gate, then chooses the lowest measured latency. Once candidates pass
--errRatio, lower error does not influence the winner. Consequently, even a tiny measured speed advantage can displace a substantially more accurate candidate; exact latency ties retain the earlier candidate regardless of accuracy.The new
--fast-scanfinal selection changes that behavior:The raw, unrounded error is retained across coarse warm-up, coarse measured-output, and final measured-output checks. A final retime cannot overwrite a larger previously observed error with a smaller one. Numerical rejection thresholds remain in force.
Illustrative example, assuming both candidates pass validation and reach final retiming:
These are illustrative values demonstrating the selection rule, not new GPU benchmark results or a claim about downstream model accuracy. The reported token-1 benchmark below selected the same kernel pair on main and the PR.
Scope: this corrects cases of unnecessary accuracy loss within the retimed finalist set. It does not guarantee the most accurate eligible candidate across the entire coarse pool, because the funnel may exclude a candidate before final retiming. The ordinary scan path without
--fast-scanremains latency-first.Sources: main's accuracy gate, main's latency-only winner selection, and PR's 1% band and accuracy-based final selection.
Main behavior addressed
gemm_moe_tune.py#L6603-L6650,common.py#L345-L379gemm_moe_tune.py#L6689-L6720(NE=288, H=4096, INTER=2048, TOPK=8)auxiliary generation and 16 tuned token tiersgen_instances.py#L17-L44,glm53_fp4_tuned_fmoe.csvCorrectness and worker-policy changes
use_cuda_event=Truesemantics could be changed by the scan worktest_common.py#L55-L110,mp_tuner.py#L57-L118,gemm_moe_tune.py#L6517-L6582gemm_moe_tune.py#L300-L374,test_fast_tuning.py#L75-L94gemm_moe_tune.py#L6757-L6860,test_fast_tuning.py#L282-L416inforeturned bymp_tuner, which remains paired with the actual task after shape grouping.gemm_moe_tune.py#L5171-L5188AITER_MAX_JOBSis the only explicit worker override. Without it, automatic sizing ismin(80% of process-available CPUs, available-memory budget)using the fixed observed 1.5 GB/worker estimate. Descendants forceAITER_MAX_JOBS=1.aiter_worker_limits.py#L181-L241,common.py#L209-L210,flydsl/README.md#L60-L83--fast-scan-itersand--fast-scan-final-itersreject values below 2 at parse time and runtime.gemm_moe_tune.py#L283-L291,test_fast_tuning.py#L44-L73README.md#L141-L174Final measured errors preserve the maximum observed error across coarse warm-up, coarse timing output, and final timing output:
gemm_moe_tune.py#L6502-L6600.Final scan policy
Fast-scan arguments and usage
The following controls are implemented by
Mxfp4FlydslTuner. Enable them with--mxfp4-flydsl --fast-scan;--fast-scanis rejected for unsupported tuner modes. An iteration here means one complete coupled MoE invocation (sorting, applicable quantization, G1, G2, and associated reduction), not one individual GPU kernel.--fast-scan--fast-scan-iters N10--fast-scan-final-iters N100--fast-scan-finalists N5--fast-scan-warmup-accuracy-checks N1In fast-scan mode, the dedicated controls above supply the measurement and warm-up counts instead of the ordinary
--iters/--warmupsettings. The existing--errRatioaccuracy gate still applies. Candidate enumeration is separate: the existing--mxfp4-search-modedefaults toprune; use--mxfp4-search-mode fullto enumerate all statically supported GEMM1 variants. The reported 174 candidate pairs describe the benchmark's configured search space, not every possible shape/search mode.Default-budget example
Run from the repository root:
The four numeric settings are shown explicitly for discoverability; omitting them uses these same defaults. For the reported 174-candidate case with no failures, this means 174 untimed warm-up/check invocations, 1,740 coarse measured invocations, and 600 final measured invocations.
Validate the generated rows through production dispatch:
Adjusting the measurement budget
For an experimental shorter final round, use the same tuning command with
--fast-scan-final-iters 32and a separate output path. Keep--fast-scan-iters 10to leave initial screening unchanged. This is an example of the configurable budget, not a claim that 32 iterations has been validated to retain every winner or reproduce the published benchmark. Increase the initial-round count when coarse rankings are unstable; adding final samples cannot recover a candidate already excluded from the finalist set.Finalists do not receive another untimed warm-up: they have already been compiled and exercised during the initial round (normally 1 untimed + 10 measured invocations). Repeating initialization warm-up is intentionally avoided. This does not assert that cache contents or GPU clock conditions remain identical between rounds. There is currently no separate final-round warm-up argument.
Timing, filtering, and selection semantics
profile_warm_iters=0, so it does not automatically discard the first profiled invocation.Q1 - 1.5*IQR/Q3 + 1.5*IQRfences and averages the retained samples. Therefore the default 10-iteration coarse round is unfiltered, whereas the 100-iteration final round is filtered. Changing 100 to 30 disables this filtering; changing it to 32 retains it. The threshold is currently hardcoded.Implementation references at the reviewed head: arguments, candidate execution and two-stage scan, and timing/filtering.
Full main-vs-PR benchmark
This is a complete token-1 measurement, not a sampled or extrapolated estimate. The performance benchmark used PR head
e438a359; the final corrective changes preserve the valid-candidate compile/timing path while fixing API, finalist, worker-policy, and validation behavior.token=1, hidden=4096, inter=2048, experts=288, topk=8dbd8bf5bd624120197a7a26780a8c72201824f0fe438a3593762cbd96e76a554e1ff4f5bffdd240d7440ef7220260901End-to-end and compile timing
Both compile-only paths covered the same 143 deduplicated jobs with zero failures. The independently observed main cold-minus-warm delta was 124.267 s, cross-checking the direct 122.814 s serial compile result.
Selected kernel and accuracy
The complete main and PR scans selected the same pair:
flydsl_mxmoe_g1_a4w4_16x256x256_f16in_ntflydsl_moe2_layout_afp4_wfp4_bf16_t16x128x256_atomic_nt_sbm16A separate common-fixture validation retimed the selected pair for 500 profiler samples: median 26.6825 us, range 26.6289-26.7627 us, worst cosine error 0.01141738, and worst tuner similarity 98.858262%.
For this shape, main and the PR select the same implementation. The PR reduces scan cost and makes selection robust to timing noise while applying accuracy only inside the global 1% performance envelope.
Corrected artifact regeneration
The corrected implementation completed a warm-cache regeneration of every GLM-5.3 token tier in 182.4143 seconds.
us16x256x256_f16in_ntt16x128x256_atomic_nt_sbm1616x256x256_f16in_ntt16x256x128_atomic_sbm1616x256x256_f16in_ntt16x128x256_atomic_nt_sbm1616x256x256_f16in_ntt16x128x256_atomic_persist_sbm1616x256x256_f16in_ntt16x128x256_atomic_persist_nt_sbm1616x256x256_f16in_ntt16x128x256_reduce_persist_nt_sbm1616x256x256_f16in_ntt16x128x256_atomic_persist_nt_sbm1616x256x256_f16in_ntt16x128x256_reduce_persist_nt_sbm1616x256x256_f16in_ntt16x128x128_atomic_nt_sbm1632x256x256_ntt32x256x128_reduce_nt_sbm3264x256x256t64x256x128_atomic_nt_sbm6464x256x256t64x256x128_atomic_nt_sbm64128x256x256t128x128x128_atomic_nt_sbm128128x256x256t128x128x256_atomic_persist_sbm12864x256x256t64x256x128_atomic_sbm6464x256x256t64x256x128_atomic_sbm64Scoped validation
Only tests directly covering the changed tuner, worker policy, and artifact were run. No broad AITER/operator test suite was used for this PR validation.
python3.14 -m pytest -q op_tests/tuning_tests/test_fast_tuning.py tests/test_worker_awareness.pypython3.14 -m py_compileof changed Python modules--mxfp4-flydsl --run_config aiter/configs/model_configs/glm53_fp4_tuned_fmoe.csvcheckAllclosewarnings are expected for lossy FP4 and are not the acceptance gate.git diff --check