Prhub

#54295 [Perf][MLA Sparse] Pin req_id_per_token before non_blocking H2D on XPU and ROCm

原始 PR 作者 JasonKeyiL 合并时间 2026-08-29 10:00 文件变更 2 提交数 1 评论 3 代码增减 +4 / -3

执行摘要

为 XPU 和 ROCm 的 MLA 稀疏元数据路径固定 H2D 拷贝源,避免 host 阻塞。

在稀疏 MLA 路径上,torch.from_numpy(...) 返回的 CPU tensor 是 pageable 的,随后的 buffer.copy_(src, non_blocking=True) 在 CUDA 驱动层会因源非 pinned 而静默地同步拷贝并阻塞 host,造成性能损失。本 PR 通过固定源内存来保持异步拷贝,属于性能修复。

该 PR 简单且安全,值得快速合入。可作为理解 vLLM 中非阻塞 H2D 拷贝和 pinned 内存重要性的参考。后续可关注是否跟进将 XPU/ROCm 收敛到 GPU 端构建路径的重构,以彻底消除 numpy 管道。

讨论亮点

无实质 review 评论,仅有 njhill 触发 CI 的指令和批准。PR 作者在正文中提及更彻底的做法是让 XPU 和 ROCm 复用 CUDA 后端的 GPU 端构建路径(token_to_req_indices),但作为较大重构留下后续跟进。

实现拆解

  1. 修改 vllm/v1/attention/backends/mla/xpu_mla_sparse.py:在 XPUMLASparseMetadataBuilder.build 中,将 self.req_id_per_token_buffer[: req_id_per_token.shape[0]].copy_(torch.from_numpy(req_id_per_token), non_blocking=True) 的源替换为 np_to_pinned_tensor(req_id_per_token),并在导入中加入 np_to_pinned_tensor。
  2. 修改 vllm/v1/attention/backends/mla/rocm_aiter_mla_sparse.py:在 ROCMAiterMLASparseMetadataBuilder.build 中执行相同替换并补充导入。
  3. 未添加测试,因为 PR 依赖 #53491 的运行时检查器来在 CI 中强制执行;此次改动仅为模式替换,无逻辑变化。
文件 模块 状态 重要度
vllm/v1/attention/backends/mla/xpu_mla_sparse.py 注意力 modified 5.11
vllm/v1/attention/backends/mla/rocm_aiter_mla_sparse.py 注意力 modified 4.98

关键符号

XPUMLASparseMetadataBuilder.build ROCMAiterMLASparseMetadataBuilder.build

关键源码片段

vllm/v1/attention/backends/mla/xpu_mla_sparse.py dependency-wiring

修改 XPU 稀疏 MLA 元数据构建器,固定 req_id_per_token_buffer 的 H2D 拷贝源。

# vllm/v1/attention/backends/mla/xpu_mla_sparse.py
# 导入中增加 np_to_pinned_tensor
from vllm.utils.torch_utils import is_quantized_kv_cache, np_to_pinned_tensor
​
# ...
def build(self, common_prefix_len, common_attn_metadata, fast_build=False):
    # ...
    # 构建每个 token 对应的请求 ID
    req_id_per_token = np.repeat(
        np.arange(seg_lengths.shape[0], dtype=np.int32), seg_lengths
    )
    # 为 cudagraph 清零缓冲区
    self.req_id_per_token_buffer.fill_(0)
    # 使用 pinned tensor 作为源进行非阻塞 H2D 拷贝,避免 host 阻塞
    self.req_id_per_token_buffer[: req_id_per_token.shape[0]].copy_(
        np_to_pinned_tensor(req_id_per_token), non_blocking=True
    )
    # ...
vllm/v1/attention/backends/mla/rocm_aiter_mla_sparse.py dependency-wiring

修改 ROCm AITER 稀疏 MLA 元数据构建器,固定 req_id_per_token_buffer 的 H2D 拷贝源。

# vllm/v1/attention/backends/mla/rocm_aiter_mla_sparse.py
# 导入中增加 np_to_pinned_tensor
from vllm.utils.torch_utils import np_to_pinned_tensor
​
# ...
def build(self, common_prefix_len, common_attn_metadata, fast_build=False):
    # ...
    # 构建每个 token 对应的请求 ID
    req_id_per_token = np.repeat(
        np.arange(seg_lengths.shape[0], dtype=np.int32), seg_lengths
    )
    # ...
    # 仅重清零收缩尾部,此处同样使用 pinned 源进行非阻塞拷贝
    self.req_id_per_token_buffer[:new_req_extent].copy_(
        np_to_pinned_tensor(req_id_per_token), non_blocking=True
    )
    # ...

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险极低。改动仅将 torch.from_numpy 替换为 np_to_pinned_tensor,后者返回一个 pinned 的 tensor 副本,语义一致。唯一潜在影响是增加一次额外的内存拷贝(从 numpy 到 pinned tensor),但这是 H2D 异步拷贝的正常前置步骤,且 np_to_pinned_tensor 有内部缓存,不会造成明显开销。未在真实 XPU/ROCm 硬件上验证,但模式替换应可安全运行。

影响范围局限于 XPU 和 ROCm 上的稀疏 MLA 注意力路径(如 DeepSeek 系列),通过消除 host 阻塞改善 prefill/decode 阶段的性能。对 CUDA 后端无影响,因为其已使用 GPU 端构建路径。负面影响极小,风险低。

缺少测试覆盖 依赖后续 CI 检查

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论