Prhub

#51425 [Perf] Narrow DeepSeek V3.2 eager CUDA graph region

原始 PR 作者 WoosukKwon 合并时间 2026-08-08 05:37 文件变更 2 提交数 1 评论 2 代码增减 +61 / -16

执行摘要

收窄 DSv3.2 eager CUDA graph 区域

PR body 指出:"The portable DeepSeek-V3.2 attention path currently decorates the entire fused attention method with eager_break_during_capture. Only the sparse indexer and backend forward_mqa call require that eager boundary"。即当前整个 _fused_attention 都被迫在 CUDA graph 捕获时中断,导致 query 准备、融合 norm/RoPE 等图安全操作以直发方式逐层重复执行,带来大量 kernel launch 开销。

值得精读,尤其是 eager 边界划分与 no-copy 权衡的决策过程;对想优化 CUDA graph 捕获效率的工程师有参考价值。建议后续跟进 forward_mqa 的 out 参数支持,并补充针对 eager 边界的回归测试。

讨论亮点

PR body 中作者详细比较了两种实现取舍:

  • No-copy 形式(本 PR 采用):UV BMM 留在 eager 区,避免拷贝 attention 输出,但牺牲了部分性能(TTFT 28.64ms)。
  • Copy 形式:额外拷一份输出到静态缓冲区并捕获 UV BMM,单测 PIECEWISE 模式下快 7.43%(26.51ms),但在默认 FULL_AND_PIECEWISE 初始化阶段 OOM,故未采用。
    • 作者也说明了本 PR 与 #50005、#47355、#47335 等历史 PR 的差异,强调本改动针对可移植 DSv3.2 attention 的 eager-boundary 边界。
      未出现实质 review 评论,CI 由 WoosukKwon 触发并通过。

实现拆解

  1. 拆分 eager 边界:在 vllm/models/deepseek_v32/attention.py 中,将原 _fused_attention 拆成两部分:图安全部分内联进 forward(A 投影、indexer 权重投影、norm/RoPE、W_UK BMM、fused_q 等),剩余依赖后端与稀疏索引的调用放入新的 _sparse_indexer_and_attn 方法并保留 @eager_break_during_capture 装饰。
  2. 保留 UV 投影在 eager 区:代码注释说明将 torch.bmm(x, self.W_UV, out=out) 留在 eager 区是为了避免拷贝 backend 的 attention 输出;一旦 forward_mqa 支持 out 参数,可再迁回图内。
  3. ROCm 子类适配:在 vllm/models/deepseek_v32/amd/rocm.py 中新增 forward 方法,保持调用旧 _fused_attention 的宽 eager 路径,确保 ROCm 平台行为不变。
  4. 测试与验证:运行 tests/v1/cudagraph/test_breakable_cudagraph.py(14 通过)与 pre-commit 检查;用 GLM-5.2 dummy 权重、TP4/EP4、FP8 KV cache 做 TTFT 基准,比较了 no-copy 与 copy 两种变体。
文件 模块 状态 重要度
vllm/models/deepseek_v32/attention.py 注意力层 modified 7.84
vllm/models/deepseek_v32/amd/rocm.py 注意力层 modified 7.15

关键符号

forward _fused_attention _sparse_indexer_and_attn

关键源码片段

vllm/models/deepseek_v32/amd/rocm.py core-logic

为 ROCm 子类新增 forward 方法,保留旧的 _fused_attention 宽 eager 路径,确保 AMD 平台行为不变。

# vllm/models/deepseek_v32/amd/rocm.py(新增 forward 方法)
​
class DeepseekV32MLAAttention(DeepseekV32Attention):
    # ... 原有初始化逻辑 ...
​
    def forward( # type: ignore[override]
        self,
        positions: torch.Tensor,
        hidden_states: torch.Tensor,
    ) -> torch.Tensor:
        # ROCm 仍走旧的宽 eager 路径:整个 _fused_attention 直发,
        # 避免与 NVIDIA 的窄边界差异导致 ROCm 后端行为改变。
        qkv_lora = self.fused_qkv_a_proj(hidden_states)[0]
        q_c, kv_c, k_pe = qkv_lora.split(
            [self.q_lora_rank, self.kv_lora_rank, self.qk_rope_head_dim], dim=-1
        )
​
        if self.indexer is not None and not self.skip_topk:
            kw = self.indexer.wk_weights_proj(hidden_states)[0]
            index_k = kw[:, : self.indexer.head_dim]
            index_weights = kw[:, self.indexer.head_dim :]
        else:
            index_k = None
            index_weights = None
​
        num_tokens = hidden_states.shape[0]
        output = torch.empty(
            (num_tokens, self.num_local_heads * self.v_head_dim),
            dtype=hidden_states.dtype,
            device=hidden_states.device,
        )
        # 调用基类中仍带 eager_break_during_capture 的旧方法
        self._fused_attention(
            positions, q_c, kv_c, k_pe, index_k, index_weights, output
        )
        return self.o_proj(output)[0]
​
    # 其余 _compute_ql_nope、_run_indexer 等方法保持不变

评论区精华

eager 边界选择:只保留 sparse indexer 与 forward_mqa 为 eager 设计

PR body 说明原实现将整个 _fused_attention 标记为 eager_break_during_capture,导致大量图安全操作以直发方式执行。作者分析只需要 sparse indexer 和 backend forward_mqa 调用需要 eager 边界。

结论:将图安全部分内联进 forward,新增 _sparse_indexer_and_attn 作为唯一 eager 区,性能显著提升。 · 已解决

no-copy 与 copy 变体的性能与 OOM 权衡 性能

copy 变体(将 backend attention 输出拷贝到静态缓冲区并捕获 UV BMM)在 PIECEWISE 模式下快 7.43%,但在 FULL_AND_PIECEWISE 默认初始化阶段 OOM。

结论:保留 no-copy 形式,UV BMM 留在 eager 区,避免输出拷贝同时保证默认模式可初始化。 · 已解决

风险与影响

  1. 核心路径变更:修改的是 DeepSeek-V3.2/GLM 系列模型的 attention 前向路径,任何边界划分错误都可能导致 CUDA graph 捕获失败或结果错误,需依赖 breakable cudagraph 测试覆盖。
  2. 平台差异:ROCm 子类新增 forward 并保留旧路径,但该 forward 是复制基类旧逻辑,后续基类继续演进时可能出现重复代码漂移;同时 AMD 路径的 eager 区依然较宽,性能收益未覆盖。
  3. 依赖 forward_mqa 接口:UV BMM 留在 eager 区是临时方案,等 forward_mqa 支持 out 参数后需再次迁移,存在后续维护成本。
  4. 测试覆盖不足:PR 未新增专门测试文件,仅依赖既有 breakable cudagraph 测试与手动基准,缺少对边界行为变化的回归保护。

对使用 NVIDIA 平台部署 DeepSeek-V3.2 或 GLM-5.2 等模型的用户,TTFT 和吞吐有接近翻倍的提升,影响显著;对 ROCm 用户无行为变化,但可能错失潜在优化。对团队而言,该改动示范了如何在 CUDA graph 捕获中精细划分 eager 边界,后续可推广到其他含稀疏索引器的模型;同时维护两条平台路径的成本略有增加。

核心路径变更 缺少直接测试文件 ROCm 平台行为差异 CUDA graph 捕获依赖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论