Prhub

#23156 [AMD] prepare for MI300x PR runner pool: registry mirror, runner routing, threshold tuning

原始 PR 作者 bingxche 合并时间 2026-04-21 15:58 文件变更 14 提交数 19 评论 7 代码增减 +145 / -117

执行摘要

为 AMD CI 准备 MI300x PR 运行器池,优化镜像拉取、动态路由并调整性能阈值。

根据PR描述,目标是为AMD CI做好准备,以便在linux-mi300-*gpu-sglang运行器池上运行PR测试,同时保持计划任务在linux-mi325-*gpu-sglang池上运行。这涉及三个耦合变更:1)使用内网镜像注册表避免PR任务频繁拉取Docker Hub导致限流;2)动态路由PR、计划任务和手动触发到不同的运行器池;3)针对MI300x硬件(相比MI325x内存带宽更低)调整测试性能预算(包括阈值、预估时间和超时),并跳过两个已知的MI300x内核级数值问题导致的非确定性测试。

该PR对于负责CI/CD基础设施和AMD平台支持的工程师非常值得精读。重点关注:

1) 如何设计镜像拉取的回退和重试策略以提升鲁棒性;
2) 如何利用GitHub Actions的表达式动态选择运行器环境;
3) 大规模性能测试阈值调整的策略和具体数值,可作为硬件平台适配的参考案例。

讨论亮点

reviewer gemini-code-assist[bot] 提出了两项主要改进建议:

  1. 避免硬编码内网注册表地址:建议在 amd_ci_start_container.shamd_ci_start_container_disagg.sh 中使用环境变量 LOCAL_DOCKER_REGISTRY 并设置默认值(${LOCAL_DOCKER_REGISTRY:-172.29.8.23:5000}),以提高脚本的可配置性和可维护性。最终代码采纳了此建议,将硬编码改为环境变量。
  2. 清理注释掉的代码:指出脚本中残留的注释行(如 CACHE_HOST=/home/runner/sglang-data)应被移除以保持代码整洁。此建议也被采纳,相关注释代码在最终提交中被删除。
    这些讨论体现了对代码质量(可维护性、清晰度)的关注,并达成了共识。

实现拆解

  1. 优化Docker镜像拉取策略以使用局域网注册表
    - 修改 release-docker-amd-nightly.ymlrelease-docker-amd-rocm720-nightly.yml:在发布夜间镜像后,新增 push_local_registry 任务,将镜像重新标记为内网注册表地址(172.29.8.23:5000/)并推送。
    - 修改 scripts/ci/amd/amd_ci_start_container.shamd_ci_start_container_disagg.sh:调整 find_latest_image 函数逻辑,不再通过 docker manifest inspect 探测内网注册表(因网络可达性问题)。在实际拉取时,优先尝试 docker pull "${LOCAL_DOCKER_REGISTRY}/${IMAGE}" 从内网注册表拉取,失败后回退到公共Docker Hub并辅以带指数退避的重试机制(retry_with_backoff)。拉取失败的错误信息会被捕获并添加 [local-pull] 前缀输出以便诊断。脚本还会在检测到 DOCKERHUB_AMD_USERNAMEDOCKERHUB_AMD_TOKEN 环境变量时执行 docker login 以提升公共拉取速率限制。
    - 在相关CI工作流文件(如 pr-test-amd.yml)的 env 块中注入上述Docker Hub凭证,确保脚本可以获取到。

  2. 根据CI触发类型动态选择AMD运行器池
    - 修改 .github/workflows/pr-test-amd.yml:将GPU密集型作业的 runs-on 从硬编码的 linux-mi325-*-sglang 改为动态表达式:${{ format('linux-{0}-Ngpu-sglang', inputs.runner_arch || (github.event_name == 'pull_request' && 'mi300' || 'mi325')) }}。这意味着:pull_request 事件使用MI300x池(更快反馈),schedule 事件使用MI325x池(全覆盖夜间测试),workflow_dispatch 事件则允许用户通过新的 runner_arch 输入进行选择(默认为 mi300)。
    - 为作业名称添加格式化,例如 name: ${{ format('stage-a-test-1-gpu-small-amd (linux-{0}-1gpu-sglang)', ...) }},使Actions UI中能清晰显示实际使用的运行器架构和GPU数量。
    - 暂时禁用了Docker构建缓存(通过条件判断)。

  3. 为MI300x硬件放宽性能测试阈值并处理已知问题
    - 修改多个性能测试文件,在 is_in_amd_ci() 条件分支中放宽延迟、吞吐量等断言阈值。例如:

    • test/registered/perf/test_bench_serving_1gpu_part2.py:对 test_vlm_offline_throughputtest_score_api_batch_scalingtest_embeddings_api_latency_throughput 等测试,将MI300x的期望输出吞吐量从2000 token/s降至900 token/s,延迟上限提高等。
    • test/registered/perf/test_bench_serving_1gpu_part1.py:移除原本在AMD CI中跳过LoRA测试的代码,并为 test_online_lora_latencytest_online_lora_latency_with_concurrent_adapter_updates 放宽TTFT(首令牌时间)阈值。
    • test/registered/moe/test_torch_compile_moe.py:在非CUDA且为AMD CI时,将吞吐量阈值从≥270 tok/s放宽至≥240 tok/s。
    • 修改 test/registered/tokenizer/test_multi_tokenizer.pytest/registered/amd/test_deepseek_v32_basic.py 等,放宽TTFT阈值或延长预估执行时间(est_time)。
    • pr-test-amd.yml 中将 stage-c 步骤的超时从90分钟延长至120分钟。
    • 使用 @unittest.skipIf(is_in_amd_ci(), ...) 跳过两个在MI300x上因内核级数值非确定性而失败的测试:
    • test/registered/sampling/test_pytorch_sampling_backend.py::test_greedy:贪心解码在多次运行间无法保证比特一致。
    • sgl-kernel/tests/test_moe_topk_sigmoid.py::test_topk_sigmoid[2048-32-4]:特定参数下sigmoid分数在fp32 ULP内时,tie-breaking逻辑与torch.topk不同(但结果仍有效)。
文件 模块 状态 重要度
.github/workflows/pr-test-amd.yml CI 流水线 modified 5.65
scripts/ci/amd/amd_ci_start_container.sh CI 脚本 modified 5.5
test/registered/perf/test_bench_serving_1gpu_part2.py 性能测试 modified 5.75
test/registered/perf/test_bench_serving_1gpu_part1.py 性能测试 modified 5.03
test/registered/sampling/test_pytorch_sampling_backend.py 采样测试 modified 3.99

关键符号

test_vlm_offline_throughput test_score_api_batch_scaling test_embeddings_api_latency_throughput test_online_lora_latency test_online_lora_latency_with_concurrent_adapter_updates test_throughput test_greedy find_latest_image

关键源码片段

scripts/ci/amd/amd_ci_start_container.sh infrastructure

负责在 AMD CI 中启动容器的关键脚本,其变更实现了优先从内网注册表拉取镜像、失败后回退到 Docker Hub 并重试的鲁棒策略,是解决 Docker Hub 限流和加速 CI 的关键。

# 定义本地注册表地址,支持通过环境变量覆盖(review 后采纳的建议)
LOCAL_DOCKER_REGISTRY="${LOCAL_DOCKER_REGISTRY:-172.29.8.23:5000}"# 在拉取镜像的主逻辑中
IMAGE=$(find_latest_image "${GPU_ARCH}")
# 优先尝试从本地注册表拉取
if local_pull_output=$(docker pull "${LOCAL_DOCKER_REGISTRY}/${IMAGE}" 2>&1); then
    echo "Pulled from local docker registry: ${LOCAL_DOCKER_REGISTRY}/${IMAGE}"
    docker tag "${LOCAL_DOCKER_REGISTRY}/${IMAGE}" "${IMAGE}"
else
    # 本地拉取失败,回退到公共注册表并重试
    echo "Local docker registry pull failed; falling back to public registry: ${IMAGE}" >&2
    printf '%s\n' "${local_pull_output}" | sed 's/^/ [local-pull] /' >&2 # 输出带前缀的错误信息便于调试
    retry_with_backoff 6 docker pull "${IMAGE}" # 指数退避重试函数
fi# 如果提供了 Docker Hub 凭证,则登录(以提升拉取速率限制)
if [[ -n "${DOCKERHUB_AMD_USERNAME}" && -n "${DOCKERHUB_AMD_TOKEN}" ]]; then
    retry_with_backoff 3 docker login -u "${DOCKERHUB_AMD_USERNAME}" -p "${DOCKERHUB_AMD_TOKEN}"
fi
test/registered/perf/test_bench_serving_1gpu_part2.py test-coverage

包含多个关键性能测试的断言阈值调整,是适配 MI300x 硬件性能(尤其是内存带宽较低)的集中体现。其变更直接影响了 CI 在 MI300x 运行器上的通过 / 失败判定。

def test_score_api_batch_scaling(self):
    """测试评分API在不同批次大小下的性能"""
    batch_sizes = [10, 25, 50]
    for batch_size in batch_sizes:
        res = run_score_benchmark(...)
        self.assertEqual(res["successful_requests"], res["total_requests"])
        # 根据是否在 AMD CI 中调整延迟边界
        if is_in_amd_ci():
            # 为 MI300x 放宽边界(HBM3 带宽较低,延迟更高)
            bounds = {10: (60, 65), 25: (70, 80), 50: (80, 90)}
            default_bounds = (90, 90)
        else:
            # 非 AMD CI(如 CUDA 或其他)保持原有严格边界
            bounds = {10: (45, 50), 25: (50, 60), 50: (60, 65)}
            default_bounds = (60, 65)
        avg_latency_bound, p95_latency_bound = bounds.get(batch_size, default_bounds)
        self.assertLess(res["avg_latency_ms"], avg_latency_bound)
        self.assertLess(res["p95_latency_ms"], p95_latency_bound)

评论区精华

使用环境变量提高脚本可配置性 设计

reviewer 建议将硬编码的内网注册表 IP 地址(172.29.8.23:5000)改为使用环境变量 `LOCAL_DOCKER_REGISTRY` 并设置默认值,以提高脚本的灵活性和可维护性。

结论:建议被采纳,代码修改为 `LOCAL_DOCKER_REGISTRY="${LOCAL_DOCKER_REGISTRY:-172.29.8.23:5000}"`。 · 已解决

清理注释掉的代码以保持代码整洁 style

reviewer 指出脚本中残留的注释代码行(如 `CACHE_HOST=/home/runner/sglang-data`)应该被移除,避免代码混乱和潜在混淆。

结论:建议被采纳,相关注释代码在最终提交中被删除。 · 已解决

风险与影响

  • 测试阈值放宽可能掩盖真实性能回归:由于MI300x硬件性能较低,多项性能测试的断言阈值被显著放宽(例如输出吞吐量从2000降至900)。虽然这是为了适应硬件差异,但可能使得在MI300x池上运行的PR测试对代码变更引入的性能退化不够敏感。
  • 硬编码配置降低可维护性:尽管review后改用了环境变量,但默认值仍指向固定的内网IP和端口(172.29.8.23:5000)。若内网注册表地址变更,需要更新多个脚本中的默认值或确保环境变量被正确覆盖。
  • 跳过测试可能隐藏潜在问题test_greedy 和特定参数的 test_topk_sigmoid 在AMD CI中被跳过,理由是MI300x上存在已知的“内核级数值抖动”。虽然这些是已知问题且也存在于MI325x基线,但跳过测试意味着在这些运行器上失去了对这些功能正确性的持续验证。
  • 运行器池切换的副作用:PR测试现在默认运行在MI300x而非MI325x上,性能基线不同。这要求工程师重新校准对CI结果中性能数字的期望,并注意比较基准的一致性。
  • 对CI系统的影响:显著提升了AMD CI的稳定性和效率。通过优先使用内网镜像注册表,减少了对外部Docker Hub的依赖和可能的限流影响,加速了镜像拉取。动态路由确保了PR测试能获得更快的反馈(使用更轻量/空闲的MI300x池),而计划任务仍能在性能更强的MI325x池上进行全覆盖测试。
  • 对开发团队的影响:提交PR的开发者将看到测试在MI300x硬件上运行,性能阈值已针对该硬件调整。团队需要了解新的性能基线(例如LoRA TTFT约慢2倍),并意识到一些非确定性测试在AMD CI中被跳过。
  • 对系统的影响:此变更纯粹是CI/CD基础设施和测试配置的调整,不影响SGLang核心运行时、模型推理逻辑或用户API。
测试阈值放松 硬编码配置 跳过测试

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论