Prhub

#49514 [ROCm][CI] Use the same-build wheel in Python-only CI

原始 PR 作者 AndreasKaratzas 合并时间 2026-08-17 11:52 文件变更 4 提交数 8 评论 13 代码增减 +182 / -88

执行摘要

ROCM Python-only CI 改用同构建 wheel 与源码 overlay

PR body 明确要求 "Package the verified checkout into the native artifact workspace and install the wheel produced by that same build",并 "Preserve the source tree and merge-base identity needed by the Python-only installation test"。此前 ROCm native artifact 工作区只包含 wheel 与测试文件,没有源码树和 .git,python_only_compile.sh 只能从 wheels.vllm.ai 拉取 merge-base 对应的预编译 wheel——这既依赖发布流水线进度(需要 5 分钟 × 5 次轮询等待 metadata 发布),又导致测试验证的并非当前 commit 的构建产物,可能掩盖新回归或产生假失败。

值得精读,尤其关注 run-amd-test.sh 中「git archive overlay + VLLM_VERSION_OVERRIDE + 同构建 wheel」的组合处理模式,这是 vLLM native/artifact CI 架构的关键一环,对理解后续 ROCm CI 演进很有帮助;同时它示范了「测试必须验证同一次构建产物」的 CI 最佳实践,对任何依赖预编译产物的项目都有参考价值。

讨论亮点
  • tjtanaa 在合并前提出顺序依赖:"I think we should merge this after this PR #49365. I have added review to #49365.",保证两个 native workspace 相关改动按序合入。
  • tjtanaa 手动触发 AMD CI 后发现 Python-only 测试组不通过:"This test group is not triggered on AMD CI... result not passing";AndreasKaratzas 定位为 "permission issue regarding creating a dir. Will check with infra",与基础设施团队确认后修复。
  • tjtanaa 在批准时再次指出门控问题:"LGTM, but I think that step is still gated behind input block? Should we enable it so that it always run now that we fixed the test?",AndreasKaratzas 回复 "I re-enabled it",随后作业恢复常态化触发。

实现拆解

  1. 测试脚本 wheel 来源重构(tests/standalone_tests/python_only_compile.sh):先探测 is_rocm(VLLM_TARGET_DEVICE / ROCM_PATH / /opt/rocm / rocminfo),ROCm 环境下优先读取 VLLM_PRECOMPILED_WHEEL_LOCATION 指定的同构建 wheel(校验文件存在且 basename 匹配 vllm-*.whl 并 realpath),否则从 legacy 镜像的 /opt/vllm-wheels 取唯一 wheel;两者都不存在时才回退到旧逻辑(CI_STANDALONE_MERGE_BASE 或 git merge-base + wheels.vllm.ai metadata.json 轮询)。安装分支新增 VLLM_PRECOMPILED_WHEEL_LOCATION 环境变量路径,走 setup.py develop --no-deps,避免无编译器环境下触发源码编译。
  2. native workspace 的源码树 overlay(.buildkite/scripts/hardware_ci/run-amd-test.sh):prepare_native_workspace 新增 test_commands 参数;当命令包含 python_only_compile.sh 时,要求 BUILDKITE_BUILD_CHECKOUT_PATH 存在且为 git worktree,校验 checkout 的 HEAD 与 artifact 记录的 recorded_commit 一致,然后用 git archive 将 verified commit 打包解压到 workspace(而非直接拷贝 worktree,避免 dirty/untracked 文件污染),并检查 setup.py、pyproject.toml、vllm 目录是否齐全。
  3. 版本与 wheel 环境变量注入:由于 overlay 故意不带 .git,setuptools-scm 无法从 git 推导版本,脚本用 importlib.metadata 读取已安装 vllm 的版本写入 VLLM_VERSION_OVERRIDE 并导出,同时把 artifact 中的 wheel 路径写入 VLLM_PRECOMPILED_WHEEL_LOCATION;在 native runtime 分支对 Python-only 作业强制 VLLM_TARGET_DEVICE=rocm,明确该 no-GPU 作业验证的是 ROCm 预编译/editable 安装路径而非 CPU 平台选择。
  4. 作业平台迁移与管道配置:.buildkite/test-amd.yaml 将 Python-only Installation 从 mi250_1(mirror_hardwares: amdgfx90anightly/amdmi250)迁到 mi300_1(amdgfx942nightly/amdmi300)并加 dind: false;.buildkite/test_areas/misc.yaml 的 AMD mirror 同步改为 device: mi300_1 与 dind: false。此前手动触发时出现目录创建权限问题,经 infra 排查后解决,review 阶段又按 tjtanaa 建议重新启用了该作业(不再是 input-gated,但 optional 标志保留)。
  5. 测试与配置配套:没有新增单元测试,验证依赖多次 Buildkite 全量 CI 与 AMD CI 手动触发结果;最终由 tjtanaa 批准合入。
文件 模块 状态 重要度
tests/standalone_tests/python_only_compile.sh 安装测试 modified 6.25
.buildkite/scripts/hardware_ci/run-amd-test.sh 作业脚本 modified 5.36
.buildkite/test-amd.yaml 流水线配置 modified 3.31
.buildkite/test_areas/misc.yaml 测试编排 modified 3.17

关键符号

prepare_native_workspace is_native_runtime

关键源码片段

tests/standalone_tests/python_only_compile.sh test-coverage

Python-only 安装测试的核心脚本,重构 wheel 来源选择逻辑,优先使用同构建 wheel,是本次变更的验证目标所在。

# 优先使用同一次构建(same-build)的 ROCm wheel,而不是去 wheels.vllm.ai
# 拉取 merge-base 对应的预编译产物,保证 Python-only CI 验证的就是当前
# commit 构建出来的 wheel。
rocm_wheel=""
is_rocm=0
_vllm_target_lower="$(printf '%s' "${VLLM_TARGET_DEVICE:-}" | tr '[:upper:]' '[:lower:]')"
if [[ "${_vllm_target_lower}" == "rocm" || -n "${ROCM_PATH:-}" || -d /opt/rocm ]] \
        || command -v rocminfo >/dev/null 2>&1; then
    is_rocm=1
fi
unset -v _vllm_target_lower
​
if [[ "${is_rocm}" == "1" ]]; then
    # Native CI 通过环境变量显式传入已验证的 wheel 产物路径;
    # legacy ROCm 镜像则把同一个构建的 wheel 放在 /opt/vllm-wheels。
    if [[ -n "${VLLM_PRECOMPILED_WHEEL_LOCATION:-}" ]]; then
        rocm_wheel="${VLLM_PRECOMPILED_WHEEL_LOCATION}"
        # 校验文件存在且命名符合 vllm-*.whl,避免误传其他路径
        if [[ ! -f "${rocm_wheel}" || "$(basename "${rocm_wheel}")" != vllm-*.whl ]]; then
            echo "ERROR: invalid ROCm wheel location: ${rocm_wheel}" >&2
            exit 1
        fi
        rocm_wheel="$(realpath -- "${rocm_wheel}")"
    elif [[ -d /opt/vllm-wheels ]]; then
        shopt -s nullglob
        rocm_wheels=(/opt/vllm-wheels/vllm-*.whl)
        shopt -u nullglob
        if [[ "${#rocm_wheels[@]}" -ne 1 ]]; then
            echo "ERROR: expected exactly one vLLM wheel in /opt/vllm-wheels, found ${#rocm_wheels[@]}." >&2
            exit 1
        fi
        rocm_wheel="${rocm_wheels[0]}"
    fi
fi# 只有拿不到本地 wheel 时才回退到 wheels.vllm.ai 的 merge-base 发布产物
if [[ -n "${rocm_wheel}" ]]; then
    echo "INFO: using same-build ROCm wheel: ${rocm_wheel}"
else
    # 旧逻辑:解析 CI_STANDALONE_MERGE_BASE 或 git merge-base,
    # 再轮询 wheels.vllm.ai 的 metadata.json(5 次 × 5 分钟)
    # ...(此处省略与 base 版本一致的 merge-base 解析与轮询代码)
fi# ROCm 场景走 setuptools develop + 预编译 wheel;--no-deps 避免在
# 无编译器环境下触发依赖源码编译。
if [[ -n "${rocm_wheel}" ]]; then
    VLLM_PRECOMPILED_WHEEL_LOCATION="${rocm_wheel}" VLLM_USE_PRECOMPILED=1 python3 setup.py develop --no-deps
elif [[ "${is_rocm}" == "1" ]]; then
    VLLM_PRECOMPILED_WHEEL_COMMIT=$merge_base_commit VLLM_USE_PRECOMPILED=1 python3 setup.py develop --no-deps
else
    VLLM_PRECOMPILED_WHEEL_COMMIT=$merge_base_commit VLLM_USE_PRECOMPILED=1 pip3 install -vvv -e .
fi
.buildkite/scripts/hardware_ci/run-amd-test.sh infrastructure

native workspace 准备逻辑的核心改动:为 Python-only 作业 overlay 完整源码树并注入 wheel/ 版本环境变量,是本次变更的机制中枢。

# prepare_native_workspace 的收尾部分:对 Python-only 安装作业,把
# Buildkite checkout 中已验证 commit 的完整源码树 overlay 到 artifact
# workspace,因为 artifact 只含 wheel + 测试工作区,没有 setup.py 和
# vllm 源码树。
if [[ "${test_commands}" == *python_only_compile.sh* ]]; then
    checkout="${BUILDKITE_BUILD_CHECKOUT_PATH:-}"
    if [[ -z "${checkout}" || ! -d "${checkout}" ]]; then
        echo "Python-only native CI requires BUILDKITE_BUILD_CHECKOUT_PATH" >&2
        return 1
    fi
    # 校验 checkout 的 commit 必须与 artifact 记录的 commit 一致,
    # 防止把其他 commit 的源码混进本次构建产物
    checkout_commit=$(
        git -c "safe.directory=${checkout}" -C "${checkout}" rev-parse HEAD
    ) || return 1
    if [[ "${checkout_commit}" != "${recorded_commit}" ]]; then
        echo "Buildkite checkout ${checkout_commit} does not match ROCm artifact ${recorded_commit}" >&2
        return 1
    fi    # overlay 故意不带 .git,setuptools-scm 无法推导版本号,
    # 所以从已安装的 wheel 里取版本,保证 editable 安装与产物一致
    VLLM_VERSION_OVERRIDE=$(
        python3 -c 'import importlib.metadata as m; print(m.version("vllm"))'
    ) || return 1
    export VLLM_VERSION_OVERRIDE
    VLLM_PRECOMPILED_WHEEL_LOCATION="${wheels[0]}"
    export VLLM_PRECOMPILED_WHEEL_LOCATION
​
    # 用 git archive 而不是直接拷贝 worktree,
    # 避免 dirty/untracked 文件污染 artifact 对应的 workspace
    git -c "safe.directory=${checkout}" -C "${checkout}" \
        archive --format=tar "${recorded_commit}" \
        | tar --no-same-owner -C "${workspace_dir}" -xf - || return 1
    for required_source in setup.py pyproject.toml vllm; do
        if [[ ! -e "${workspace_dir}/${required_source}" ]]; then
            echo "Full source checkout is missing ${required_source}" >&2
            return 1
        fi
    done
fi

评论区精华

合并顺序:先合 #49365 other

tjtanaa 在评论中表示应等 #49365 合并后再合本 PR,并已对 #49365 添加 review;两个 PR 同属 ROCm native/artifact workspace CI 演进。

结论:按协作顺序等待 #49365 先合,本 PR 随后合入。 · 已解决

AMD CI 上 Python-only 测试组未自动触发且手动运行失败 other

tjtanaa 手动触发 AMD CI 后结果不通过;AndreasKaratzas 定位为创建目录的权限问题,需要咨询 infra。

结论:与基础设施团队协作解决权限问题后测试通过。 · 已解决

作业是否仍被 input block 门控 other

tjtanaa 批准时指出该 step 仍被 input block 门控,建议在测试修复后启用使其总是运行;AndreasKaratzas 回复已重新启用并提供 Buildkite 链接。

结论:作业已重新启用,纳入常规触发(optional 标志保留)。 · 已解决

风险与影响

  1. run-amd-test.sh 的 commit 一致性校验非常严格:若 Buildkite checkout 与 artifact 记录的 commit 不一致,Python-only 作业会直接失败(fail fast);但由于分支只对包含 python_only_compile.sh 的作业生效,不影响其他 native 作业。
  2. VLLM_VERSION_OVERRIDE 依赖已安装 wheel 的版本元数据(importlib.metadata),若 artifact 中 vllm 未安装或安装损坏会失败;同时 overlay 用 git archive 整体覆盖 workspace,若 artifact 中恰好有同名目录(如 vllm/)会被源码树覆盖。
  3. 作业平台从 mi250_1 迁移到 mi300_1 并启用 dind: false:若 mi300 镜像缺少运行该脚本的条件(如 /opt/vllm-wheels 布局差异),作业可能失败;目前有 optional: true(test-amd.yaml)与 soft_fail: true(misc.yaml mirror)缓冲。
  4. 对 wheels.vllm.ai 外部依赖的解除是正向变化,但保留了完整回退路径,双路径维护略微增加脚本复杂度。

影响范围为 AMD/ROCm CI 的 Python-only Installation 测试组及其运行平台:测试保真度提升(验证同构建产物)、稳定性提升(不再受 wheels.vllm.ai 发布时序和 5 分钟轮询影响)、并解除了对 merge-base 旧产物的隐式依赖。对产品代码和最终用户无感知;对 CI 维护团队而言,作业平台迁移(mi250→mi300)与 input gate 重新启用会带来一定的运维关注成本,但整体收益大于成本。

平台迁移(mi250→mi300) VLLM_VERSION_OVERRIDE 依赖已安装 wheel git archive overlay 覆盖工作区文件

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论