Prhub

#24314 Deprecate record_nolora_graph dual MoE CUDA graph capture

原始 PR 作者 sshleifer 合并时间 2026-05-16 10:20 文件变更 4 提交数 1 评论 1 代码增减 +39 / -129

执行摘要

废弃 dual MoE CUDA graph 双路捕获功能

PR body 明确指出 dual-capture 路径是 "a bug factory and not that fast",并且在 #23727 和 #23873 中持续暴露出混合 LoRA / 无 LoRA 重放时的正确性问题。因此决定回退该特性,回归更简洁的 CUDA 图捕获方案。

建议关注 LoRA CUDA 图捕获的开发者仔细阅读此 PR。它展示了面对特性复杂化时的回退决策过程,以及在 Triton kernel 中利用早期退出实现零开销条件化的技巧。

讨论亮点

本 PR 未引发实质性讨论。gemini-code-assist[bot] 的自动评论无反馈意见,随后获得 yushengsu-thu 和 Fridge003 两位维护者的 Approve。

实现拆解

  1. 移除配置项:在 ServerArgs 中删除 record_nolora_graph 字段及对应 CLI 参数 --record-nolora-graph
  2. 移除全局状态:在 python/sglang/srt/layers/moe/utils.py 中删除 RECORD_NOLORA_GRAPH 全局变量、should_record_nolora_graph() 函数及其在 initialize_moe_config() 中的赋值逻辑。
  3. 简化 graph 管理:在 python/sglang/srt/model_executor/cuda_graph_runner.py 中移除模块级变量 _capture_lora_variant、访问函数 get_capture_lora_variant/_set_capture_lora_variant,以及 _default_make_graph_key/_make_graph_key/_resolve_lora_variant 方法,恢复 key 只包含 (bs, stream_idx)。
  4. 统一 LoRA 录制:在 python/sglang/srt/lora/lora_moe_runners.py 中删除 _add_lora_gate_up_delta_add_lora_down_deltabuild_lora_hooks 三处的 nolora 早期退出,改为在 capture 模式中始终执行 LoRA 路径,利用 Triton kernel 在 adapter_enabled 全零时的零开销早期退出。
  5. 测试无配套变更,依赖现有 LoRA CUDA graph CI(如 test_lora_cuda_graph)。
文件 模块 状态 重要度
python/sglang/srt/model_executor/cuda_graph_runner.py 图运行器 modified 8.74
python/sglang/srt/layers/moe/utils.py MoE 配置 modified 6.89
python/sglang/srt/lora/lora_moe_runners.py LoRA 运行器 modified 6.5
python/sglang/srt/server_args.py 服务参数 modified 5.31

关键符号

get_capture_lora_variant _set_capture_lora_variant _default_make_graph_key _make_graph_key _resolve_lora_variant should_record_nolora_graph _add_lora_gate_up_delta _add_lora_down_delta build_lora_hooks

关键源码片段

python/sglang/srt/model_executor/cuda_graph_runner.py data-contract

核心变更文件,移除了双变体捕获的模块状态、访问函数和 graph key 构造方法,大幅简化 CUDA 图捕获逻辑。

# 变更后 : 移除了 _capture_lora_variant 及其访问函数,graph key 恢复为仅包含 (bs, stream_idx)
# _capture_lora_variant: Optional[str] = None # 已删除
# def get_capture_lora_variant() ... # 已删除
# def _set_capture_lora_variant(...) ... # 已删除def get_is_capture_mode():
    return is_capture_mode# graph key 构造 : 不再包含 variant_label
# 原 _default_make_graph_key(bs, stream_idx, variant_label) 已移除
# 捕获循环中直接使用 (bs, stream_idx) 作为键
python/sglang/srt/lora/lora_moe_runners.py dependency-wiring

删除了三个 nolora 早期退出检查,改为始终录制 LoRA 路径;新增 has_active_lora 逻辑,在 capture 模式强制为 True,依赖 kernel 内部零开销退出。

def _add_lora_gate_up_delta(
    hidden_states: torch.Tensor,
    intermediate_cache: torch.Tensor,
    ...
) -> None:
    """Add LoRA gate_up delta to intermediate_cache in-place."""
    from sglang.srt.lora.triton_ops import fused_moe_lora, merged_experts_fused_moe_lora_add
​
    if get_is_capture_mode():
        # After deprecation: always record LoRA path during capture.
        # adapter_enabled is all-zeros, so the Triton kernel early-exits
        # per program (zero overhead).
        has_active_lora = True
    else:
        num_loras = len(lora_info.lora_ranks)
        has_active_lora = (
            (
                lora_info.adapter_enabled[:num_loras]
                * (lora_info.lora_ranks > 0).to(lora_info.adapter_enabled.dtype)
            )
            .any()
            .item()
        )
    if not has_active_lora or lora_info is None or lora_info.max_lora_rank == 0:
        return
    # ... rest of the function unchanged

评论区精华

自动代码审查 other

gemini-code-assist[bot] 评论表示无反馈意见。

结论:无实质性讨论,PR 随后获得两位维护者批准。 · 已解决

风险与影响

主要风险在于移除了 nolora 图形路径后,纯无 LoRA 推理场景可能因始终执行 LoRA kernel 而产生额外开销。但 PR 依赖 Triton kernel 在 adapter_enabled 全零时的程序级早期退出途径,理论上零开销。此外,cuda_graph_runner 中的 graph key 构造简化可能影响与子类(如 EAGLEDraftCudaGraphRunner)的兼容性,需确保子类不依赖已移除的方法。

对用户:--record-nolora-graph CLI 选项失效,但默认值为 True,移除后不再产生双套 CUDA 图,可能略微降低显存占用和捕获时间。对系统:CUDA 图捕获逻辑简化,消除了双变体同步引入的正确性隐患。对团队:减少约 129 行有问题的代码,降低维护负担。

移除优化路径 核心路径变更 回退设计

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论