执行摘要
- 一句话:支持XPU流水线并行,设备无关化并修复死锁
- 推荐动作:值得精读,尤其是设备无关化和奇偶通信策略的设计。对于需要支持多后端(AMD、MUSA 等)的团队,此为可复用的模式。PR 的 review 讨论也展示了如何识别并修复因初始化顺序导致的问题。
功能与动机
Pipeline parallelism (PP) only ran on CUDA. On Intel XPU, launching any --pp-size > 1 server crashed at startup with RuntimeError: Tried to instantiate dummy base class Event because SchedulerPPMixin hard-codes torch.cuda.{Event, current_stream, synchronize}. Even after fixing the hard-coded CUDA calls, PP >= 2 livelocked during the first multi-rank communication: with XCCL on XPU, torch.distributed.isend busy-polls waiting for a matching recv rendezvous, so when every PP rank sent before receiving, all ranks spun at 100% CPU inside torch.distributed and none ever reached its recv.
实现拆解
1. 设备无关化
在 scheduler_pp_mixin.py 中,将对 torch.cuda.Event()、torch.cuda.current_stream()、torch.cuda.synchronize() 的调用替换为通过 get_device_module() 返回的设备模块的动态调用,并更新类型提示(torch.cuda.Event → torch.Event)。
2. 奇偶顺序 send/recv
在 _pp_send_recv_and_preprocess_output_tensors 中,基于 PP rank 的奇偶性调整 send 和 recv 的执行顺序,仅在 XPU 上生效。偶数 rank 先 send 后 recv,奇数 rank 先 recv 后 send,确保每一对相邻 rank 的 isend 都有匹配的等待 recv。
3. 修复 profile_and_init_predictor 的初始化顺序
使用模块级函数 get_device_module() 替代 self.device_module,因为 profile_and_init_predictor 在 Scheduler.init_overlap 之前调用,self.device_module 尚未赋值。
关键文件:
python/sglang/srt/managers/scheduler_pp_mixin.py(模块 调度器;类别 source;类型 core-logic;符号 _do_send, _do_recv): PR 的唯一变更文件,核心调度器混入类,包含设备无关化、奇偶通信顺序及初始化修复。
关键符号:event_loop_pp, event_loop_pp_disagg_prefill, event_loop_pp_disagg_decode, _pp_send_recv_and_preprocess_output_tensors, _pp_commit_send_output_work_and_preprocess_output_tensors, init_pp_loop_state, profile_and_init_predictor, _do_send, _do_recv
关键源码片段
python/sglang/srt/managers/scheduler_pp_mixin.py
PR 的唯一变更文件,核心调度器混入类,包含设备无关化、奇偶通信顺序及初始化修复。
# 设备无关化:用 self.device_module.current_stream() 替代 torch.cuda.current_stream()
# 在 event_loop_pp 中
if not self.pp_group.is_last_rank:
if self.cur_batch:
self.device_module.current_stream().wait_event(self.launch_event)
with torch.profiler.record_function("send_proxy_dict_to_next_stage"):
self.send_proxy_work = self._pp_send_dict_to_next_stage(
result.pp_hidden_states_proxy_tensors.tensors,
async_send=True,
msg_type="proxy",
)
# 修复 profile_and_init_predictor 中设备同步的初始化顺序
# 使用 get_device_module() 替代 self.device_module(可能未赋值)
def profile_and_init_predictor(self: Scheduler):
# ...
device_module = get_device_module()
device_module.synchronize() # 替代 torch.cuda.synchronize()
start = time.perf_counter()
# ... 模型前向推理 ...
device_module.synchronize()
latency = time.perf_counter() - start
# ...
评论区精华
讨论 1: torch.Event 类型提示
- gemini-code-assist[bot] 建议将
torch.Event 替换为 Any,因为旧版 PyTorch 没有顶层 Event 类。
- siju-samuel 回应:项目要求 PyTorch ≥ 2.9,
torch.Event 在 PyTorch 2.4 后已是公共类,保留更具体的类型提示更清晰。
- 结论:未采纳建议,类型提示保持不变。
讨论 2: profile_and_init_predictor 中 self.device_module 未初始化
风险与影响
- 风险:
- 类型提示兼容性:
torch.Event 在 PyTorch < 2.4 不可用,但项目基线为 2.9,风险可控。
- XPU 特定代码路径:奇偶顺序仅当
is_xpu() 为真时生效,CUDA 路径不受影响。测试已覆盖 CUDA 下的 PP 正确性。
- 动态分块依赖:修复前
profile_and_init_predictor 会静默失败并禁用动态分块;修复后行为正确,但仍需确保各初始化路径顺序。
- 单一文件修改:所有改动集中在
scheduler_pp_mixin.py,回归范围明确。
- 影响:
- XPU 用户:现在可以使用
--pp-size > 1 进行多卡流水线并行,LLM 推理吞吐量显著提升(benchmark 显示 PP=4 时输入吞吐 13051 tok/s)。
- CUDA 用户:无任何行为变化,因
get_device_module() 在 CUDA 上返回 torch.cuda,且奇偶顺序仅对 XPU 生效。
- 其他后端:设备无关化设计为未来在 AMD、NPU 等后端启用 PP 扫清了障碍。
- 维护影响:后续任何后端都只需在
get_device_module() 中注册,无需修改调度器逻辑。
- 风险标记:核心调度器变更, XPU特定代码路径, 动态分块初始化顺序依赖
关联脉络
- PR #23472 [Intel GPU] Enable pipeline parallelism on XPU: 为前一个被回退的同一功能PR,本PR为其第二版,修复了死锁和初始化问题。
- PR #23641 Revert "[Intel GPU] Enable pipeline parallelism on XPU": 回退预览版PR,因CI中断;本PR在其基础上重新实现并修复问题。
参与讨论