Prhub

#41313 [ROCm][CI] Fix NIXL spec-decode acceptance startup and diagnostics

原始 PR 作者 AndreasKaratzas 合并时间 2026-05-10 14:50 文件变更 5 提交数 3 评论 2 代码增减 +137 / -27

执行摘要

修复 ROCm NIXL 猜测解码集成测试启动与诊断

HTTP 就绪检查不足以判断 NIXL side-channel 是否可用,导致测试在 decode 阶段因 side-channel 未就绪而超时。需要精确探测 side-channel 元数据就绪状态,并确保所有网络流量(HTTP、代理、NIXL side-channel)使用同一 loopback 地址以避免 IPv4/IPv6 不匹配。

该 PR 值得阅读,特别是测试框架中的异步服务就绪检查模式(进程存活与端点探测结合)值得参考。对于分布式测试的时序稳定性和错误诊断有良好示范。建议作者在后续 PR 中考虑 review 中关于异常类型和 IPv6 兼容性的反馈。

讨论亮点

在 review 中,gemini-code-assist[bot] 提出了两点建议:

  • 使用更具体的异常类型(如 RuntimeError)而非 AssertionError 来表示运行时配置不匹配,以区分内部逻辑错误。
  • 在 shell 脚本的 curl 命令中处理 IPv6 地址,以避免未来当 SERVER_HOST 被设置为 IPv6 地址时 URL 格式错误。
    目前这两个建议尚未被采纳或回复,建议作者后续考虑。

实现拆解

  1. 新增 side-channel 探测工具nixl_side_channel_probe.py):通过 ZMQ REQ 套接字发送 get_meta_msg 并在超时前等待响应,判断 side-channel 是否真正就绪。
  2. 修改集成测试脚本spec_decode_acceptance_test.sh):
    • wait_for_server 函数中添加进程存活检查 (ps -p),若目标进程已退出则立即失败,避免空轮询到超时。
    • 新增 wait_for_nixl_side_channel 函数,调用探测脚本来确认 side-channel 就绪。
    • 引入 SERVER_HOSTNIXL_SIDE_CHANNEL_HOST 变量,默认 127.0.0.1,确保所有 HTTP 和 ZMQ 连接使用同一地址族。
    • run_test_for_device 中,启动每个实例后先等待其完成就绪再启动下一个,减少资源争抢。
  3. 调整测试验证脚本test_spec_decode_acceptance.py):将所有硬编码 localhost 替换为 SERVER_HOST 环境变量,与 shell 脚本保持一致。
  4. 增强 NIXL worker 诊断worker.py):
    • 改进日志输出,打印所有 attention backend 名称而非仅第一个。
    • 将 KV cache 块数不匹配的断言改为引发 AssertionError,并附带层名、形状、步幅、后端列表、KV 布局、拓扑模式等上下文,便于快速定位。
  5. 更新 CI 配置test-amd.yaml):将 ROCM_ATTN=1 替换为 ATTENTION_BACKEND=ROCM_ATTN,使注意力后端选择与其他测试统一。
文件 模块 状态 重要度
tests/v1/kv_connector/nixl_integration/nixl_side_channel_probe.py 侧信道探测 added 6.97
vllm/distributed/kv_transfer/kv_connector/v1/nixl/worker.py 分布式核心 modified 6.49
tests/v1/kv_connector/nixl_integration/spec_decode_acceptance_test.sh 集成测试 modified 5.94
tests/v1/kv_connector/nixl_integration/test_spec_decode_acceptance.py 验证测试 modified 4.36
.buildkite/test-amd.yaml CI 配置 modified 3.28

关键符号

parse_args make_zmq_path main wait_for_server wait_for_nixl_side_channel

关键源码片段

tests/v1/kv_connector/nixl_integration/nixl_side_channel_probe.py test-coverage

新增 NIXL side-channel 探测工具,通过 ZMQ REQ 发送 get_meta_msg 并等待响应以确认信道就绪。

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Probe a NIXL side-channel socket for handshake metadata readiness."""import argparse
import ipaddressimport msgspec
import zmq# 固定的消息内容
GET_META_MSG = b"get_meta_msg"
​
​
def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument("--host", required=True)
    parser.add_argument("--port", required=True, type=int)
    parser.add_argument("--rank", default=0, type=int)
    parser.add_argument("--timeout-ms", default=1000, type=int)
    return parser.parse_args()
​
​
def make_zmq_path(host: str, port: int) -> str:
    try:
        # 若 host 是 IPv6 地址,需用方括号括起来
        if isinstance(ipaddress.ip_address(host), ipaddress.IPv6Address):
            return f"tcp://[{host}]:{port}"
    except ValueError:
        pass
    return f"tcp://{host}:{port}"
​
​
def main() -> None:
    args = parse_args()
    ctx = zmq.Context()
    sock = ctx.socket(zmq.REQ)
    sock.setsockopt(zmq.LINGER, 0) # 关闭时立即丢弃未发送消息
    sock.setsockopt(zmq.RCVTIMEO, args.timeout_ms) # 接收超时
    try:
        sock.connect(make_zmq_path(args.host, args.port))
        sock.send(msgspec.msgpack.encode((GET_META_MSG, args.rank)))
        # 阻塞等待响应,若超时会抛出 zmq.Again 异常
        sock.recv()
    finally:
        sock.close()
        ctx.term()
​
​
if __name__ == "__main__":
    main()
vllm/distributed/kv_transfer/kv_connector/v1/nixl/worker.py core-logic

增强 KV cache 注册时的断言信息,输出层名、形状、步幅、后端列表、布局和拓扑模式。

# 在 register_kv_caches 方法中,当 cache.shape[0] != num_blocks 时,
# 原来简单的 assert 被替换为详细的 AssertionError,附带丰富的调试信息:
if cache.shape[0] != num_blocks:
    raise AssertionError(
        "All kv cache tensors must have the same number of "
        f"blocks; layer={layer_name}, "
        f"expected_num_blocks={num_blocks}, "
        f"cache_shape={tuple(cache.shape)}, "
        f"cache_stride={tuple(cache.stride())}, "
        f"layer_spec={type(layer_spec).__name__}, "
        f"backend={self.backend_name}, "
        "all_backends="
        f"{[backend.get_name() for backend in self.attn_backends]}, "
        f"kv_cache_layout={self.kv_cache_layout}, "
        "blocks_first="
        f"{self.transfer_topo.is_kv_layout_blocks_first}"
    )
tests/v1/kv_connector/nixl_integration/spec_decode_acceptance_test.sh test-coverage

增加服务进程存活检查,添加 NIXL side-channel 就绪等待函数,参数化主机地址。

# 新增的 side-channel 等待函数
wait_for_nixl_side_channel() {
  local host=$1
  local port=$2
  local server_pid=$3
  local server_name=$4
  local deadline=120
  local elapsed=0
  echo "Waiting for ${server_name} NIXL side channel on ${host}:${port}..."
  while [ $elapsed -lt $deadline ]; do
    # 若服务进程已终止,则立即失败,避免空轮询
    if ! ps -p "$server_pid" > /dev/null 2>&1; then
      local status=0
      wait "$server_pid" || status=$?
      echo "FAIL: ${server_name} server process ${server_pid} exited with status ${status} before NIXL side channel ${host}:${port} became ready"
      exit 1
    fi
    # 调用 Python 探测脚本
    if python3 "${GIT_ROOT}/tests/v1/kv_connector/nixl_integration/nixl_side_channel_probe.py" \
      --host "$host" \
      --port "$port" \
      --timeout-ms 1000 > /dev/null 2>&1
    then
      echo "${server_name} NIXL side channel on ${host}:${port} ready"
      return 0
    fi
    sleep 2
    elapsed=$((elapsed + 2))
  done
  echo "FAIL: ${server_name} NIXL side channel ${host}:${port} did not start within ${deadline}s"
  exit 1
}

评论区精华

异常类型使用建议 设计

gemini-code-assist 建议将 AssertionError 改为更具体的 RuntimeError 或 ValueError,因为配置不匹配并非内部逻辑错误,而是外部输入问题。

结论:当前仍保留了 AssertionError,但提供了更丰富的上下文。作者未回复该建议。 · unresolved

IPv6 地址兼容性 正确性

gemini-code-assist 指出 curl 命令中直接使用 ${SERVER_HOST} 构造 URL,当 SERVER_HOST 为 IPv6 地址时会导致 curl 解析失败,建议添加 IPv6 检测。

结论:评论未得到采纳或回复,当前脚本仍存在该潜在问题。 · unresolved

风险与影响

主要风险包括:

  • 测试流程变更wait_for_serverwait_for_nixl_side_channel 的新逻辑可能因进程状态检查的竞态条件导致误判,但已增加进程存在检测降低风险。
  • 新增依赖zmqmsgspec 需在 CI 环境中预装,若缺失则探测脚本会失败。
  • IPv6 兼容性:shell 脚本中 curl 构造 URL 时未处理 IPv6 地址,若未来 SERVER_HOST 设为 IPv6 地址会导致 URL 格式错误。
  • 生产代码无风险worker.py 的改动仅增强诊断,逻辑等价。

影响范围仅限于 ROCm CI 中的 NIXL 猜测解码集成测试步骤(v1/kv_connector/nixl_integration/spec_decode_acceptance_test.sh)。该测试用于验证分布式猜测解码(PD+SD)的接受长度匹配基线。变更后测试启动更健壮,诊断信息更丰富,有助于快速定位 side-channel 和 KV cache 相关失败。生产代码无影响。

测试流程变更 新增依赖(zmq, msgspec) IPv6 未充分处理

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论