Skip to content

[AMD] dsr1 mi355x disagg 8k1k mtp: fix gsm8k collapse at conc >= 1024 - #2466

Closed
Duyi-Wang wants to merge 1 commit into
mainfrom
duwang/fix-mla-persist-highconc
Closed

[AMD] dsr1 mi355x disagg 8k1k mtp: fix gsm8k collapse at conc >= 1024#2466
Duyi-Wang wants to merge 1 commit into
mainfrom
duwang/fix-mla-persist-highconc

Conversation

@Duyi-Wang

Copy link
Copy Markdown
Collaborator

Opened as a draft — the change is validated on hardware, but I am not requesting merge until a maintainer confirms the scoping is what you want.

Problem

The 2P1D entry of dsr1-fp4-mi355x-sglang-disagg-8k1k-mtp collapses on gsm8k at high concurrency. On 2 prefill + 1 decode node, conc 2048, full gsm8k 5-shot: strict-match 0.0023. Generations are truncated after a handful of tokens rather than wrong, which is why it reads as a total failure rather than a quality regression.

Cause

job.slurm defaults SGLANG_AITER_MLA_PERSIST to 0, selecting the non-persistent aiter MLA decode. That path leaves num_kv_splits to aiter's python-side auto-search in mla_decode_fwd. Under CUDA graphs that python runs once, at capture — so the split count, and the partial buffers sized from it, are frozen and reused for every replay. Above roughly 128 running requests per DP rank the frozen choice corrupts decode.

Only this entry reaches that point: with dp8, per-rank batch is conc/8, so conc 1024 → 128 and up. conc ≤ 640 stays below it and is unaffected.

Evidence

Single-node bisection, image 20260729, client concurrency 2048, varying only the server admission cap:

cap peak batch/rank strict-match
256 32 0.9530
512 64 0.9500
1024 128 0.9530
2048 165 0.0356

Same failing point, one variable changed at a time:

change strict-match
SGLANG_AITER_MLA_PERSIST=1 0.9530
--disable-cuda-graph 0.9492
speculative decoding off 0.0879 (still broken — not an MTP defect)
bf16 KV instead of fp8 0.0265 (still broken — not a KV defect)

Two prefill + one decode node, conc 2048 — the configuration this entry actually runs:

strict-match flexible-extract
SGLANG_AITER_MLA_PERSIST=0 0.0023 0.0023
SGLANG_AITER_MLA_PERSIST=1 0.9469 0.9477

An accept-length of 1.997 (ceiling 2.0) in the failing runs initially looked like a speculative-decode verification defect; disabling speculative decoding entirely still fails, so that was a symptom, not the cause.

Why scoped rather than flipping the job.slurm default

The persistent MLA reduce had its own defect — an LDS write-after-read race in mla_reduce_v1_impl_massive, where __builtin_amdgcn_s_barrier() emits no s_waitcnt lgkmcnt(0) and no memory fence, so wave 1 reads p_lds_lse_scale before wave 0's writes land and corrupts output channels [256, 512). aiter fixed that in cdd6628f9. Configs still pinned to an older image must keep the non-persistent path, so flipping the global default would trade this bug for that one on every other AMD multi-node config.

Hence: the image here is pinned to 20260729 (which carries cdd6628f9) and the persistent path is enabled for this one entry only. The inline comment states that dependency so the two are not separated later.

Note dsr1-fp4-mi355x-sglang-disagg-mtp has a structurally identical 2P1D entry but a different image; I have deliberately not touched it.

Verification

CI dispatched on this branch for dsr1-fp4-mi355x-sglang-disagg-8k1k-mtp --conc 2048 --evals-only (2P1D, eval-only).

🤖 Generated with Claude Code

The 2P1D entry of dsr1-fp4-mi355x-sglang-disagg-8k1k-mtp collapses on gsm8k at
high concurrency. Measured on 2 prefill + 1 decode node, conc 2048, full gsm8k
5-shot: strict-match 0.0023.

Cause: job.slurm defaults SGLANG_AITER_MLA_PERSIST to 0, selecting the
non-persistent aiter MLA decode. That path leaves num_kv_splits to aiter's
python-side auto-search in mla_decode_fwd; under CUDA graphs that python runs
once at capture, so the split count -- and the partial buffers sized from it --
are frozen and reused for every replay. Above roughly 128 running requests per
DP rank the frozen choice corrupts decode. Only this entry reaches that point
(1024/8 = 128 and up); conc <= 640 stays below it and is unaffected.

Single-node bisection, image 20260729, client concurrency 2048, varying only
the server admission cap:

  cap  peak batch/rank  strict
  256   32              0.9530
  512   64              0.9500
  1024  128             0.9530
  2048  165             0.0356

Same failing point, one variable changed at a time:
  SGLANG_AITER_MLA_PERSIST=1   0.9530
  --disable-cuda-graph         0.9492
  speculative decoding off     0.0879  (still broken; not an MTP defect)
  bf16 KV instead of fp8       0.0265  (still broken; not a KV defect)

Two prefill + one decode node, conc 2048, the configuration this entry runs:
  SGLANG_AITER_MLA_PERSIST=0   0.0023
  SGLANG_AITER_MLA_PERSIST=1   0.9469

Scoped to this one entry rather than flipping the job.slurm default, because
the persistent MLA reduce had its own defect (an LDS write-after-read race,
wave 1 corrupting output channels [256, 512)) that aiter only fixed in
cdd6628f9. Configs still pinned to an older image must keep the non-persistent
path, so the image here is pinned to 20260729, which carries that fix.
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase As a PR reviewer and CODEOWNER, I have reviewed this and have.

For PR verification, add the full-sweep-fail-fast label (strongly recommended) to this PR — the benchmark sweep only runs on labeled PRs. Use full-sweep-enabled only if you need matrix jobs to keep running past a failure.

PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs


感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 As a PR reviewer and CODEOWNER, I have reviewed this and have

如需进行 PR 验证,请为此 PR 添加 full-sweep-fail-fast 标签(强烈推荐)— 基准测试 sweep 仅在带有标签的 PR 上运行。仅当需要矩阵任务在失败后继续运行时才使用 full-sweep-enabled

PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant