执行摘要
- 一句话:按节点数拆分 MI355X nightly 测试为 2N/4N 两阶段
- 推荐动作:值得快速浏览。重点看两点:一是按硬件拓扑拆分 CI 矩阵的模式(关键字分组 + 空矩阵跳过 + 未匹配报错),对多节点 nightly 测试有通用参考价值;二是 YAML anchor 复用步骤的写法,可作为团队内部 CI job 模板化的范本。AMD/CI 相关的维护者可精读,其余成员了解即可。
功能与动机
PR body 未填写具体动机(仅为模板内容)。从变更本身看,原 workflow 仅支持 2 节点 1P1D 的 MI355X 配置,本次将 nightly 扩展为同时覆盖 2 节点与 4 节点(-2p1d-ep16)两类拓扑,按节点数分组便于分别调度与控制并行度,并在遇到未识别拓扑时直接失败,避免配置漂移导致漏测。
实现拆解
- setup 阶段拆分矩阵:在
.github/workflows/nightly-amd-mi355x-disagg.yml 中,将原来只输出 matrix 的步骤改为输出 matrix-2n 与 matrix-4n 两个结果。内嵌 Python 脚本按配置名关键字 -1p1d / -2p1d-ep16 分组,未匹配的拓扑会触发 SystemExit,防止新增配置被静默漏测。
- 2 节点 job 重命名:
nightly-mi355x-benchmark 更名为 nightly-mi355x-2n,消耗 needs.setup.outputs.matrix-2n,并增加矩阵为空的跳过条件(needs.setup.outputs.matrix-2n != '{"include":[]}'),避免空矩阵空跑。
- 新增 4 节点 job:新增
nightly-mi355x-4n,依赖 setup 与 nightly-mi355x-2n,消耗 matrix-4n,max-parallel 设为 1,避免与 2 节点阶段抢同一批 MI355X 自托管节点。
- YAML anchor 复用:将
env 定义为 &mi355x-env、steps 定义为 &mi355x-steps,两个 job 通过 *mi355x-env / *mi355x-steps 引用,保证后续调整步骤只改一处。
- 结果聚合调整:
collect-results 改为同时依赖 nightly-mi355x-2n 与 nightly-mi355x-4n,并在 always() 下执行,两个阶段任一失败都会反映到汇总结果。
关键文件:
.github/workflows/nightly-amd-mi355x-disagg.yml(模块 CI 工作流;类别 infra;类型 infrastructure): 这是该 PR 唯一修改的文件,承载全部 CI 逻辑:setup 阶段按节点数拆分矩阵、新增 4 节点 job、通过 YAML anchor 复用步骤并调整结果聚合依赖。
关键符号:未识别
关键源码片段
.github/workflows/nightly-amd-mi355x-disagg.yml
这是该 PR 唯一修改的文件,承载全部 CI 逻辑:setup 阶段按节点数拆分矩阵、新增 4 节点 job、通过 YAML anchor 复用步骤并调整结果聚合依赖。
# 1) setup job 中,把整份配置矩阵按节点数拆成两个输出
MATRIX="$MATRIX" python3 - <<'PY'
import json
import os
matrix = json.loads(os.environ["MATRIX"])
# "-1p1d" 命中 2 节点拓扑,"-2p1d-ep16" 命中 4 节点拓扑
groups = {
"matrix-2n": [entry for entry in matrix if "-1p1d" in entry["name"]],
"matrix-4n": [entry for entry in matrix if "-2p1d-ep16" in entry["name"]],
}
matched = {entry["name"] for entries in groups.values() for entry in entries}
unmatched = [entry["name"] for entry in matrix if entry["name"] not in matched]
if unmatched:
# 出现未识别拓扑直接失败,防止 nightly 悄悄漏测新配置
raise SystemExit("Unrecognized MI355X topology for config(s): " + ", ".join(unmatched))
with open(os.environ["GITHUB_OUTPUT"], "a") as output:
for name, entries in groups.items():
value = {"include": [{"config": entry} for entry in entries]}
print(f"{name}={json.dumps(value, separators=(',', ':'))}", file=output)
PY
# 2) 2 节点与 4 节点 job 通过 YAML anchor 复用环境变量与步骤
nightly-mi355x-2n:
strategy:
fail-fast: false
max-parallel: 2
matrix: ${{ fromJson(needs.setup.outputs.matrix-2n) }}
env: &mi355x-env
FRAMEWORK: sglang
HW: mi355x
steps: &mi355x-steps
- name: Launch MI355X benchmark
timeout-minutes: 180
nightly-mi355x-4n:
needs: [setup, nightly-mi355x-2n]
strategy:
fail-fast: false
max-parallel: 1
matrix: ${{ fromJson(needs.setup.outputs.matrix-4n) }}
env: *mi355x-env
steps: *mi355x-steps
评论区精华
该 PR 没有 review 评论线程,仅由 bingxche 直接批准。两个 commit([CI] Stage MI355X nightly by node count 与 [CI] Reuse MI355X benchmark steps across stages)体现了先拆分矩阵、再抽取公共步骤的重构顺序,说明作者在实现过程中自行完成了可维护性取舍。
风险与影响
- 风险:
- YAML anchor 耦合:
&mi355x-env / &mi355x-steps 被两个 job 共享,若未来 2N 与 4N 需要差异化运行参数或步骤,需先拆 anchor,否则会互相影响。
- 矩阵分组依赖配置名:分组逻辑基于配置名中的
-1p1d / -2p1d-ep16 关键字,若 nightly-configs.yaml 新增其他拓扑而未同步更新分组脚本,setup 会直接 SystemExit,导致整个 nightly 失败;这是有意为之的防御,但也提高了后续维护门槛。
- 4 节点 job 依赖链:
nightly-mi355x-4n 依赖 2 节点阶段完成,虽然使用 !cancelled() 避免 2N 失败时 4N 被取消,但 2N 失败时 4N 仍会继续申请 MI355X 节点,资源开销可能翻倍。
- 无配套测试:矩阵拆分逻辑只在真实 nightly 中验证,PR 未包含任何单测或语法校验步骤。
- 空矩阵判断:
matrix-4n 为空时的跳过条件写法为字符串比较 !='{"include":[]}',与 setup 输出格式强耦合,格式变化会静默失效。
- 影响:影响范围严格限于 AMD MI355X 的 nightly CI 流程:从原先只跑 2 节点 1P1D,扩展为同时跑 2 节点与 4 节点(2P1D EP16)两类拓扑,新增了一个持续约数小时的 4 节点测试路径。对端到端推理功能、模型输出和用户 API 无任何影响;对团队而言,AMD nightly 的维护者需要关注新 job 的资源调度与稳定性,自托管 runner 的并发占用会明显增加。
- 风险标记:YAML anchor 复用, 矩阵分组依赖配置名, 新增 4 节点测试路径, collect-results 依赖变更, 无配套测试
关联脉络
- PR #31483 [AMD] ci: run vetted nested multimodal_gen unit tests on AMD: 同为 AMD 平台的 CI 能力扩展,与本 PR 共同反映 AMD 测试覆盖持续演进的方向。
参与讨论