[AMD][AgentX] dsv4 vllm-agentic MTP: pin the 08-09 nightly + additive container patches / dsv4 vllm-agentic MTP:改钉 08-09 nightly 并增量打补丁 - #2589
Conversation
… container patches
The dsv4-fp4-mi355x-vllm-agentic-mtp config cannot start on its pinned image:
the server memory-faults during the profile run, before it ever serves a
request. Repin to the 08-09 nightly (f8d03e77) and patch it before serving.
The fault is in the base, not in anything this recipe does. It reproduces
identically on a PRISTINE 08-12 nightly (3ee2df30) with no patches applied at
all: the eight TP workers serialize on /tmp/aiter_configs/bf16_tuned_gemm.csv
.lock, and the worker holding the baton dies in the post-MoE bf16 GEMM while
the other seven survive parked on the lock. Two separate standalone repros
clear the loudest suspects -- the inter_dim=384 MoE returns finite results at
the exact faulting shape with preshuffled weights, and the bf16 GEMM passes on
all four paths at M=65536 and M=16384 x N=7168 x K=7168.
apply_dsv4_container_patches.sh is strictly additive and idempotent:
vllm #51473 native MXFP4 TP8 shard allocation. Merged 2026-08-11, i.e.
AFTER this base, so unlike the 08-12 nightly it has to be
applied here.
vllm #51714 opt-in AITER gluon sparse-MLA decode for gfx950.
vllm #51918 vllm/config/kernel.py ONLY, registering the flydsl_mega_moe
backend name. The model-side hunks are deliberately not taken:
the backend needs mori.ir.flydsl, which this base does not
have, so a DEP8 row is now rejected at config time with a clear
error instead of failing deep inside a kernel.
aiter #4417 large-token FlyDSL MoE launch/output limits. The upstream diff
does not apply (the base predates aiter's typing modernization,
so every context line still reads Dict[str, Dict]), so the
hunks are grafted by anchor.
Nothing that ships in the base is overwritten. Three of the four
pa_decode_sparse variants already ship and are left alone -- only the gfx950
one is genuinely missing. An earlier revision copied all four out of
aiter@97d0c6e4 and silently replaced base files with a cross-version
transplant; the script now skips anything already present, and re-running it is
a verified no-op.
中文:dsv4-fp4-mi355x-vllm-agentic-mtp 在其固定镜像上根本起不来 —— 服务在 profile
run 阶段发生显存访问越界,还没开始服务请求就崩了。本 PR 将镜像改钉到 08-09 的
nightly(f8d03e77),并在启动前打补丁。
该故障出在基座本身,与本 recipe 无关:在完全未打任何补丁的 08-12 原始 nightly
(3ee2df30)上可以复现出完全相同的签名 —— 8 个 TP worker 在
/tmp/aiter_configs/bf16_tuned_gemm.csv.lock 上串行排队,持有 baton 的那个 worker
在 MoE 之后的 bf16 GEMM 中死亡,其余 7 个因阻塞在锁上而幸存。两个独立的最小复现
排除了最显眼的两个嫌疑对象:inter_dim=384 的 MoE 在完全相同的形状和预 shuffle 权重
下返回有限值;bf16 GEMM 在 M=65536 与 M=16384 × N=7168 × K=7168 下四条路径全部通过。
apply_dsv4_container_patches.sh 严格只做增量,且幂等。基座自带的文件一律不覆盖:
四个 pa_decode_sparse 变体中有三个基座已自带,脚本予以保留,只补真正缺失的 gfx950
那一个。早前的版本曾把四个文件全部从 aiter@97d0c6e4 拷入,等于用跨版本的文件静默
替换了基座文件;现在脚本会跳过任何已存在的文件,重复执行已验证为 no-op。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
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 For PR verification, add the 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 模板,包括保留英文语句 如需进行 PR 验证,请为此 PR 添加 PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档 |
Adds docs/waiver/2589.md per docs/PR_REVIEW_CHECKLIST.md, covering the apply_dsv4_container_patches.sh invocation in dsv4_fp4_mi355x_vllm_mtp.sh, and replaces the PRNUM placeholder in perf-changelog.yaml with the real PR number. The waiver records both halves of why no pinned image serves this config unmodified: the newer nightly line memory-faults during the profile run on a pristine, unpatched container, and the older 08-09 line that does not fault predates vllm #51473 (merged 2026-08-11). It also states what is deliberately NOT patched -- three of the four pa_decode_sparse variants ship in the base and are left untouched, aiter core is not modified, and #51918's model-side hunks are skipped because the base has no mori.ir.flydsl. 为 #2589 补交 docs/PR_REVIEW_CHECKLIST.md 要求的镜像补丁豁免文档,并把 perf-changelog.yaml 中的 PRNUM 占位符替换为真实 PR 号。豁免文档记录了两个固定 镜像都无法原样跑通该配置的原因,以及补丁栈刻意「不做」的部分。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An earlier `git add -A` in this worktree picked up ~70 local bring-up scratch files (dotted probe scripts, alternative serve variants, spur job stdout, raw PR diffs) that have no business in the repo. Only the six intended files remain: the patch script and its aiter graft helper, the recipe, the master config, the waiver, and the changelog entry. 清理早前 `git add -A` 误扫入分支的约 70 个本地调试脚本,仅保留应提交的 6 个文件。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e #4417 graft The patch stack went in as "stock base + upstream PRs", but three knobs it claimed or implied were reachable were not. sparse gluon was silently dead. An earlier revision copied only the gfx950 gluon kernel and deliberately left the three pa_decode_sparse variants that ship in the base untouched, to avoid a cross-version transplant. That was the right instinct and the wrong call for the facade: the base's aiter/ops/triton/attention/pa_decode_sparse.py predates the extra_cache / extra_indices / extra_indptr keywords that vllm #51714's call site passes, so with VLLM_ROCM_DSV4_SPARSE_GLUON=1 all eight workers raised TypeError: pa_decode_sparse() got an unexpected keyword argument 'extra_cache' on first decode and latched onto the Triton fallback for the life of the process. The knob was accepted, logged as on, and inert. The facade and the kernel it dispatches to now move together, and the verify step asserts the accepted keywords by signature introspection -- file presence is exactly what gave the false positive. MegaMoE and FSE are now reachable. mori/ir/flydsl is 3 plain .py files, not a compiled artifact, but they drag in the cov cascade: runtime.py calls find_bitcode(cov=6) and cov threads through ir/bitcode.py, jit/cache.py and jit/core.py (37 upstream call sites, 0 in the base) plus jit/config.py for is_debuginfo_enabled. Partial installs fail in that exact order. FSE needs aiter fhmoe plus _flydsl_moe_stage1_impl/_flydsl_moe_stage2_impl, which live in a moe_kernels.py the base does not have; that file is the one wholesale replacement, AST symbol-diffed first (58 -> 66 symbols, 0 lost, 8 gained). With mori.ir.flydsl present, #51918's model-side hunks are no longer pointless, so it now applies in full across all 6 files. graft_aiter_4417.py is deleted. #4417 ships in the aiter@97d0c6e4 moe_kernels.py installed above (grep -c = 5), and neither guard can fire here regardless: requires_flydsl_stage2_reduce first fires at 299594 tokens against this recipe's 65536 ceiling, and resolve_flydsl_grid_y_persist_m returns persist_m=1 with 8x of headroom under the grid.y cap. The sweep grid varies concurrency only. Everything is sourced from aiter@97d0c6e4 or mori@84a33cc -- no private image, no binary payloads (libmori_shmem_device.bc is JIT-compiled in-container with hipcc on first import). Verified from scratch on a container created from the pinned image: 21 steps, VERIFY: ALL_OK, and a second run reports same / already present for all of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Superseded: reopening without any container patching, per the repo owner's rule that recipes must run the pinned image as published. The replacement PR keeps the 08-09 nightly pin and carries only recipe- and sweep-config-level tuning. 已关闭并由新 PR 取代:按仓库所有者的要求,配方不得对镜像打任何补丁,必须直接运行已发布的镜像。替代 PR 保留 08-09 nightly 镜像钉定,仅包含配方层与 sweep 配置层的调优。 |
Summary
Waiver:
docs/waiver/2589.mddsv4-fp4-mi355x-vllm-agentic-mtpcannot start on its pinned image — the server memory-faults during the profile run, before it ever serves a request. This PR repins it to the 08-09 nightly (f8d03e77) and patches the image before serving viaapply_dsv4_container_patches.sh, which is the combination local bring-up actually gets toApplication startup completeon.The fault is in the base, not in this recipe's patches. It reproduces identically on a pristine 08-12 nightly (
3ee2df30) with no patches applied at all: the eight TP workers serialize on/tmp/aiter_configs/bf16_tuned_gemm.csv.lock, and the worker holding the baton dies in the post-MoE bf16 GEMM while the other seven survive parked on the lock. Two standalone repros clear the loudest suspects — theinter_dim=384MoE returns finite results at the exact faulting shape with preshuffled weights and the same kernel pair, and the bf16 GEMM passes on all four paths (gemm_a16w16_opus, asm, triton, torch) at both M=65536 and M=16384 × N=7168 × K=7168. It is non-deterministic across runs (different worker, different address, different kernel selection), which is why it is filed as a base regression under separate investigation rather than fixed here.nightly-821717118f…→nightly-f8d03e77416bf90c49acbe50e233275722f02c4b. The entry carries a comment telling the next person not to bump it without re-running bring-up.apply_dsv4_container_patches.sh, strictly additive + idempotent, marker-gated):fused_moe/oracle/mxfp4.py)VLLM_ROCM_DSV4_SPARSE_GLUON=1vllm/config/kernel.pyonly — registers theflydsl_mega_moebackend nameDict[str, Dict]), so the hunks are grafted by anchor viagraft_aiter_4417.py_gluon_kernels/gfx950/attention/pa_decode_sparse.pypa_decode_sparsevariants already ship and are left alone. An earlier revision of this script copied all four out ofaiter@97d0c6e4, silently replacing base files with a cross-version transplant; the script now skips anything already present, and a verified re-run is a clean no-op (keep base×4, graftSKIP, all PRsalready present).#51918is taken partially on purpose. MegaMoE's intranode kernel importsmori.ir.flydsl, which this base does not have (verifiedModuleNotFoundError), so applying the model hunks would buy a backend that raises on first use. Registering only the backend name means a DEP8 row is rejected at config time with a clear error instead of failing deep inside a kernel. DEP8/MegaMoE is out of scope on this route.VLLM_ROCM_DSV4_SPARSE_GLUON=1is defaulted on (overridable). The knob is read viaos.environrather thanenvs.py, so vLLM logs it asUnknown vLLM environment variable— that warning is expected and does not mean it was ignored.Sweep label
full-sweep-enabledrather than thefull-sweep-fail-fastthatAGENTS.md:95recommends as the default. Justification: this config is coming back from not starting at all, so the first full sweep is as much a bring-up probe as a measurement. Under fail-fast the first flaky point cancels that matrix's remaining jobs and throws away in-flight results from the concurrency points that did work — exactly the "flaky config where one flake would kill a matrix's in-flight results" caseAGENTS.md:95names as the reason to reach forfull-sweep-enabled. Once the config has a green sweep this should go back tofull-sweep-fail-fast.8k-in / 1k-out @ concurrency 32
Run on the patched 08-09 image (hold job 6707, node crsuse2-m2m-100), mirroring CI's
run_benchmark_servinginvocation (--random-range-ratio 0,--num-prompts 320,--max-concurrency 32,--ignore-eos):Acceptance length lands at 2.49, exactly the
synthetic_acceptance_lengthpinned in the recipe — the MTP fan-out behaves as the campaign measured it. Position-2 acceptance is 0.00% by construction: synthetic rejection is configured to stop there.Plumbing route
Picking explicitly, per the handover's "do not silently pick one": Option 1 — keep the knobs inside the benchmark recipe (env-overridable defaults), do not extend the sweep-config schema. Rationale: Option 2 touches
validation.py,generate_sweep_configs.pyandrun-sweep.yml:596-630, i.e. shared sweep infrastructure every config rides on, in service of one config that today cannot even start. That is the wrong order — earn the schema change after the config is green. Option 1's cost is that per-arm knobs live in the recipe rather than the YAML search-space; the measured price of the recipe-side default at c32 was −4.9%, which is a known, bounded, documented tradeoff rather than a shared-infrastructure risk. This PR is the minimal form of Option 1: the patch invocation plus the gluon env, with no schema change. If a later arm genuinely needs a per-row knob the YAML cannot express, that is the moment to revisit Option 2 on its own PR.Test plan
apply_dsv4_container_patches.shapplies cleanly on a fresh container of the pinned image, and re-running it is a verified no-oppy_compile+ import checks pass in-container for every patched modulegenerate_sweep_configs.py full-sweep --config-files configs/amd-master.yaml --model-prefix dsv4 --framework vllmgenerates all 8 agentic rows on the new image with no schema errorApplication startup completeon the patched 08-09 image — the profile run and cudagraph capture, where the old pin faulted, both complete中文说明
dsv4-fp4-mi355x-vllm-agentic-mtp在其固定镜像上根本起不来 —— 服务在 profile run 阶段发生显存访问越界,还没开始服务请求就崩了。本 PR 将镜像改钉到 08-09 的 nightly(f8d03e77),并通过apply_dsv4_container_patches.sh在启动前打补丁;这个组合是本地 bring-up 真正能跑到Application startup complete的组合。该故障出在基座本身,与本 recipe 的补丁无关。 在完全未打任何补丁的 原始 08-12 nightly(
3ee2df30)上可以复现出完全相同的签名:8 个 TP worker 在/tmp/aiter_configs/bf16_tuned_gemm.csv.lock上串行排队,持有 baton 的那个 worker 在 MoE 之后的 bf16 GEMM 中死亡,其余 7 个因阻塞在锁上而幸存。两个独立的最小复现排除了最显眼的嫌疑对象:inter_dim=384的 MoE 在完全相同的形状、相同 kernel 组合、预 shuffle 权重下返回有限值;bf16 GEMM 在 M=65536 与 M=16384 × N=7168 × K=7168 下四条路径全部通过。它在不同运行之间是非确定性的(worker、地址、kernel 选择都不同),因此这里将其作为基座回归单独跟进,而不是在本 PR 中修复。nightly-821717118f…→nightly-f8d03e77416bf90c49acbe50e233275722f02c4b。配置项中留有注释,提醒后来者不要在未重跑 bring-up 的情况下升级它。pa_decode_sparse变体中有三个基座已自带,脚本予以保留,只补真正缺失的 gfx950 那一个。早前版本曾把四个文件全部从aiter@97d0c6e4拷入,等于用跨版本文件静默替换了基座文件;现在脚本会跳过任何已存在的文件,重复执行已验证为 no-op。mori.ir.flydsl,这个基座没有(已验证ModuleNotFoundError),打上模型侧的 hunk 只会得到一个一用就抛异常的后端。只注册后端名字,可以让 DEP8 行在配置阶段被明确拒绝,而不是深入 kernel 之后才失败。DEP8/MegaMoE 在本路线中不在范围内。synthetic_acceptance_length完全一致。validation.py、generate_sweep_configs.py和run-sweep.yml:596-630这些所有配置共用的 sweep 基础设施,而受益方只是一个目前连起都起不来的配置 —— 顺序不对,应当先让配置转绿再谈 schema 改动。Option 1 的代价是每个 arm 的旋钮位于 recipe 而非 YAML search-space;recipe 侧默认值在 c32 实测代价为 −4.9%,这是已知、有界、且已记录的取舍。full-sweep-enabled而非AGENTS.md:95推荐的默认full-sweep-fail-fast。理由是这个配置是从「完全无法启动」恢复过来的,第一次全量 sweep 与其说是测量不如说是 bring-up 探测;在 fail-fast 下,第一个不稳定的点会取消该 matrix 其余作业并丢弃那些本已跑通的并发点的在途结果 —— 这正是AGENTS.md:95中所述应当改用full-sweep-enabled的情形。一旦该配置有了一次绿色 sweep,应改回full-sweep-fail-fast。🤖 Generated with Claude Code