Skip to content

perf: MI355X DSv4.1 Flash on the ROCm nightly image with the CK a8w4 MoE experts / MI355X DSv4.1 Flash 切换 ROCm nightly 镜像并选择 CK a8w4 MoE 专家内核 - #3058

Open
Fangzhou-Ai wants to merge 9 commits into
mainfrom
config/dsv41flash-moe-ck
Open

perf: MI355X DSv4.1 Flash on the ROCm nightly image with the CK a8w4 MoE experts / MI355X DSv4.1 Flash 切换 ROCm nightly 镜像并选择 CK a8w4 MoE 专家内核#3058
Fangzhou-Ai wants to merge 9 commits into
mainfrom
config/dsv41flash-moe-ck

Conversation

@Fangzhou-Ai

@Fangzhou-Ai Fangzhou-Ai commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Supersedes #3035 and targets main directly, so the MI355X DSv4.1 Flash recipe lands in one self-consistent state. #3035 is frozen and its five commits are carried here unchanged (rebased onto current main); this PR adds the MoE backend change on top. #3035 can be closed once this merges.

Carried from #3035:

New here: the MoE backend change described below.

Summary

The recipe pinned --moe-backend aiter_triton_mxfp4_bf16. That name maps to exactly one entry, the Triton W4A16 kernel, so decode ran _moe_gemm_a16w4. Passing plain aiter opens vLLM's full priority list, whose head is the Composable Kernel backend, and the experts become the a8w4 family the DSV4-Pro MI355X recipe already uses:

mfma_moe1_silu_mul_afp8_wfp4_bf16_t32x128x256_pm1_async_gui_v33.kd
mfma_moe2_afp8_wfp4_bf16_cshuffle_t32x128x128_vscale_fix3_fp4opt_v1_pm1.kd

Two things made this non-obvious, so the flag carries a comment: the backend is named ..._BF16, and this checkpoint declares activation_scheme: dynamic with no input_scale tensors. vLLM's explicit W4A8 path does require static FP8 activation scales and correctly refuses, but CK quantizes activations to FP8 inside the kernel and needs no checkpoint scales.

Decode traces

Both arms captured on the same four GPUs, TP4, 131k context, CUDA graphs active, 50 engine steps, identical profiler settings. Per-rank busy spread was under 1% on both.

conc MoE GEMM ms/step whole step ms gain
1 2.72 → 2.30 19.11 → 18.31 4.2%
4 4.91 → 4.27 19.42 → 18.40 5.3%
16 9.06 → 7.18 28.38 → 25.92 8.7%

CK replaces one fused Triton kernel with two CK GEMMs plus its own sorting and gating kernels, so the expert-GEMM win (29-46%) is larger than the whole-step win. The whole-step column is the one that matters.

A separate steady-state decode benchmark run on the opposite GPU half agreed in direction and size (ITL 2.1% / 4.8% / 6.3% better at conc 1 / 4 / 16), which rules out GPU-half asymmetry as the explanation.

AgentX replay, conc 1

Each arm ran solo on a quiet node. A first attempt ran the two arms concurrently on the two halves and the CK lane died on a 600 s NCCL all-gather timeout inside capture_model — two simultaneous CUDA-graph captures contend and desync the ranks. Serial is both safer and the right baseline for a latency comparison.

metric Triton CK gain
ITL mean 4.01 ms 3.91 ms 2.5%
TTFT mean 681 ms 639 ms 6.2%
e2e mean 4.48 s 4.32 s 3.6%

Both arms used AIPERF_EXPERIMENTAL_FAST=1 (20-minute profiling window), so these absolute numbers are not comparable to a full-duration reference run; the delta is.

Accuracy

gsm8k 5-shot at conc 8, same lane configuration as the baseline run, is unchanged to four decimal places:

filter Triton CK
strict-match 0.9719 ± 0.0045 0.9719 ± 0.0045
flexible-extract 0.9712 ± 0.0046 0.9712 ± 0.0046

Notes

  • The AITER OPUS sparse-prefill kernel from [ROCm][Perf] Route large DSV4 sparse prefill to AITER OPUS vllm-project/vllm#54855 was checked at the same time and needs no change: Using AITER OPUS for large sparse MLA prefill on gfx950 is already in every server log on this image.
  • The mHC RMSNorm fusion DSV4-Pro gets (aiter::mhc_pre_big_fuse_rmsnorm_kernel) is not reachable here and is not part of this PR. AITER ships no delayed mHC kernel at all, so vLLM composes the delayed pre block from mhc_pre_gemm_sqrsum + mhc_pre_big_fuse + a Triton collapse, and only the non-delayed mhc_pre takes a norm_weight. Closing that gap needs a new AITER kernel; the ceiling looks like 2-3% of decode.

Note

Medium Risk
Touches serving image, MoE kernel selection, and scheduler limits for a production AgentX recipe; accuracy was reported unchanged on gsm8k but broader GPU validation is still marked pending.

Overview
Updates dsv41flash-fp4-mi355x-vllm-agentic-dspark so MI355X AgentX serving matches the intended upstream ROCm stack and avoids AgentX scheduling bottlenecks.

Container and docs: configs/amd-master.yaml and the benchmark script now pin vllm/vllm-openai-rocm:nightly-eed1f3d0c6043bd494424a22443ee198dd56f657 instead of deepseekv41-flash-0909, because the release tag predates vLLM #56503 (mHC delayed pre on AITER). English and Chinese configuration docs reflect the new image and MoE flag.

Benchmark script (dsv41flash_fp4_mi355x_vllm_mtp.sh): Sets AITER_TRITON_LOG_LEVEL=ERROR to cut Gluon fallback noise from logs. Raises MAX_NUM_SEQS to 128 (from 2*CONC) so AgentX subagent fan-out is not capped at two in-flight sequences at CONC=1. Changes --moe-backend from aiter_triton_mxfp4_bf16 to aiter so vLLM selects CK a8w4 expert kernels (aligned with DSV4-Pro MI355X) rather than the Triton W4A16 path.

Changelog: perf-changelog.yaml adds three append-only entries for this config key documenting the nightly bump, scheduler change, and MoE backend switch (with measured perf notes in the descriptions).

Reviewed by Cursor Bugbot for commit ab76c13. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

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 关于重新运行失败任务的文档

Comment thread perf-changelog.yaml Outdated
description:
- "Switch --moe-backend from aiter_triton_mxfp4_bf16 to aiter, which selects the CK a8w4 experts (mfma_moe1_silu_mul_afp8_wfp4_bf16 / mfma_moe2_afp8_wfp4_bf16) instead of the W4A16 _moe_gemm_a16w4 Triton kernel, matching the DSV4-Pro MI355X recipe. Decode traces at 131k context show MoE GEMM falling from 2.72 to 2.30 ms/step at conc 1, 4.91 to 4.27 at conc 4 and 9.06 to 7.18 at conc 16, for whole-step gains of 4.2%, 5.3% and 8.7%. AgentX conc 1 improves mean ITL 4.01 to 3.91 ms and mean TTFT 681 to 639 ms; gsm8k is unchanged at 0.9719 strict-match."
- "将 --moe-backend 从 aiter_triton_mxfp4_bf16 改为 aiter,从而选择 CK a8w4 专家内核(mfma_moe1_silu_mul_afp8_wfp4_bf16 / mfma_moe2_afp8_wfp4_bf16),取代 W4A16 的 _moe_gemm_a16w4 Triton 内核,与 DSV4-Pro MI355X 配方保持一致。131k 上下文的解码 trace 显示 MoE GEMM 在并发 1 时从 2.72 降至 2.30 ms/step,并发 4 从 4.91 降至 4.27,并发 16 从 9.06 降至 7.18,整步分别加速 4.2%、5.3% 和 8.7%。AgentX 并发 1 的平均 ITL 从 4.01 降至 3.91 ms,平均 TTFT 从 681 降至 639 ms;gsm8k strict-match 保持 0.9719 不变。"
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/PENDING

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 pr-link uses pull/PENDING, which is neither the canonical pull/<number> pattern nor a recognized placeholder (XXX / pull/XXX), so validate_added_pr_link in infx/workflows/validate_perf_changelog.py will raise ChangelogValidationError and fail the changelog-gate CI check, blocking merge until fixed. Fix: use the XXX placeholder convention (or pull/XXX) that the validator and prepare_perf_changelog_merge.py actually recognize and auto-canonicalize on merge.

Extended reasoning...

infx/workflows/validate_perf_changelog.py defines PR_LINK_PLACEHOLDERS = {"XXX", ".../pull/XXX"} and CANONICAL_PR_LINK requiring \d+; validate_added_pr_link (called from the CI changelog gate) raises ChangelogValidationError for any link that is neither the canonical numeric link nor one of those exact placeholders. pull/PENDING matches neither, so the gate fails with 'new PR entry must use ... or an XXX placeholder; found ...'. This must be fixed before merge, and prepare_perf_changelog_merge.py's canonicalize_appended_links also only rewrites entries whose link is in PR_LINK_PLACEHOLDERS, so PENDING would also break the merge-time link substitution.

Verification: normal — perf-changelog.yaml:7422 adds pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/PENDING. This is neither the canonical numeric link (CANONICAL_PR_LINK at validate_perf_changelog.py:21-23 requires /pull/\d+) nor a recognized placeholder (PR_LINK_PLACEHOLDERS at :24-27 is exactly {"XXX", ".../pull/XXX"}). validate_added_pr_link (:144-160) raises ChangelogValidationError…

@Fangzhou-Ai
Fangzhou-Ai force-pushed the config/dsv41flash-moe-ck branch from 6677759 to 637c3f9 Compare September 12, 2026 15:10
@Fangzhou-Ai
Fangzhou-Ai changed the base branch from config/dsv41flash-mi355x-nightly to main September 12, 2026 15:10
@Fangzhou-Ai
Fangzhou-Ai requested a review from a team September 12, 2026 15:10
Fangzhou-Ai and others added 5 commits September 12, 2026 15:15
The deepseekv41-flash-0909 tag predates vllm-project/vllm#56503, which
moves the mHC delayed pre block off the eager Torch reference and onto
AITER. That block is 85% of the decoder's kernel launches for this model,
so the release tag leaves most of the decode cost unaddressed.

Tag is nightly-TBD until the first nightly containing that commit is
published; it is then pinned to nightly-<sha> like the other ROCm entries.
AITER's Triton MoE GEMM logs "GLUON backend not available. Using TRITON
backend!!!" on every call. Gluon supports only gfx1250, so on gfx950 the
message reports a fixed property of the hardware rather than a condition,
and it dominates the server log: 410,984 of 417,504 lines in a gsm8k run,
29.8 MiB of 32 MiB.

Set AITER_TRITON_LOG_LEVEL=ERROR, the knob aiter.ops.triton.utils.logger
reads. Every warning that module emits is about Gluon availability -- the
two Gluon GEMM depth fallbacks are inside gfx1250-only paths, and
fused_mxfp4_quant warns only when Gluon is requested explicitly -- so
raising the threshold hides nothing actionable on this architecture.

Log hygiene rather than performance: the emits run at 61/s per worker and
4.33 us each, or 0.026% of wall time.

Signed-off-by: Fangzhou Ai <fangzhou@semianalysis.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
The 2*CONC cap sat below AgentX's subagent fan-out. At CONC=1 the engine
admitted 2 requests and queued the rest on scheduling capacity, with vLLM
reporting queue times up to 16.2 s. Removing the cap takes queue time to
zero at identical output.
The nightly containing vllm-project/vllm#56503 is out:
nightly-eed1f3d0c6043bd494424a22443ee198dd56f657
(sha256:960228cf..., published 2026-09-12). Replace the nightly-TBD
placeholder in the config, recipe header, and both docs, and record the
upstream recipe PR that moves vllm-project/recipes to the same image.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Fangzhou-Ai
Fangzhou-Ai force-pushed the config/dsv41flash-moe-ck branch from 637c3f9 to 4346a82 Compare September 12, 2026 15:17
@Fangzhou-Ai Fangzhou-Ai changed the title perf: select the CK a8w4 MoE experts on MI355X DSv4.1 Flash / MI355X DSv4.1 Flash 选择 CK a8w4 MoE 专家内核 perf: MI355X DSv4.1 Flash on the ROCm nightly image with the CK a8w4 MoE experts / MI355X DSv4.1 Flash 切换 ROCm nightly 镜像并选择 CK a8w4 MoE 专家内核 Sep 12, 2026
@Fangzhou-Ai
Fangzhou-Ai force-pushed the config/dsv41flash-moe-ck branch from 4346a82 to 1c62aee Compare September 12, 2026 15:19
The recipe pinned --moe-backend aiter_triton_mxfp4_bf16, which names a
single W4A16 entry and dispatched _moe_gemm_a16w4. Passing plain aiter
opens vLLM's priority list, whose head is the Composable Kernel backend,
and CK quantizes activations to FP8 internally: the decode trace
switches to mfma_moe1_silu_mul_afp8_wfp4_bf16 and
mfma_moe2_afp8_wfp4_bf16, the same a8w4 expert family the DSV4-Pro
MI355X recipe already runs. The BF16 in the backend name and this
checkpoint's activation_scheme=dynamic both suggest otherwise, hence the
comment at the flag.

Measured on one MI355X half, TP4, 131k context, CUDA graphs on, both
arms captured on the same four GPUs under identical profiling overhead:

  conc   MoE GEMM ms/step      whole step ms
   1     2.72 -> 2.30          19.11 -> 18.31   (4.2%)
   4     4.91 -> 4.27          19.42 -> 18.40   (5.3%)
  16     9.06 -> 7.18          28.38 -> 25.92   (8.7%)

AgentX replay at conc 1, each arm solo on a quiet node, improves mean
ITL from 4.01 to 3.91 ms and mean TTFT from 681 to 639 ms. gsm8k is
unchanged: 0.9719 +/- 0.0045 strict-match, 0.9712 +/- 0.0046 flexible,
identical to the Triton arm.

Signed-off-by: Fangzhou Ai <31551580+Fangzhou-Ai@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

@chunfangamd

Copy link
Copy Markdown
Collaborator

/stage-results 34710937012

@github-actions

github-actions Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

@chunfangamd staged run 34710937012: https://inferencemax-app-git-staging-semianalysisai.vercel.app/inference?i_dates=2026-09-12~r34710937012

This run remains available across future /stage-results requests. Staging the same run ID again updates its staged data. Staging workflow

@chunfangamd

Copy link
Copy Markdown
Collaborator

/reuse-sweep-run 34710937012

@chunfangamd

Copy link
Copy Markdown
Collaborator

vllm-project/recipes#962

@cursor

cursor Bot commented Sep 13, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants