Prhub

#13397 [sgl-kernel][CPU] add kernel for shm_allgather_into_tensor and shm_reduce_scatter_tensor

原始 PR 作者 chunyuan-w 合并时间 2026-07-23 09:19 文件变更 5 提交数 5 评论 2 代码增减 +232 / -13

执行摘要

新增 CPU 共享内存 allgather_into_tensor 和 reduce_scatter_tensor 内核

在 CPU 上实现 DP attention 需要高效的 allgather 和 reduce_scatter 原语,PR #12961 中的慢路径将被这两个内核替换。此外,现有 naive_all_gather 函数因重用状态组和缓冲区,在多 rank 跨阶段场景下可能导致挂起或错误结果,需一并修复。

值得精读。重点了解:如何通过 STATE_GROUP 模板参数避免竞争条件;allreduce_workspace 的偏移量宏扩展机制;测试文件从 manual 迁至 registered 并注册 CI 的流程。

讨论亮点

本 PR 无 review 评论,由 mingfeima 直接批准。关键设计决策已在 PR body 中阐明:使用模板参数 STATE_GROUP 区分不同操作的状态索引,避免状态污染;扩展 allreduce_workspace 结构体以容纳 5 个状态组和对应双缓冲区;shm_reduce_scatter_tensor 仅支持 SUM 归约以保持简单。

实现拆解

  1. 隔离状态组与缓冲区:将 allreduce_workspace 中的 states 数组从 2 扩展到 5,为每个分布式操作分配独立状态槽位;通过 STATE_GROUP_* 常量(定义在 shm.h)索引,并用模板参数 STATE_GROUPall_gather 函数模板化,确保不同操作使用互不干扰的状态机和双缓冲区。

  2. 新增 shm_allgather_into_tensor:在 interface.cpp 中实现 shm_allgather_into_tensor 函数,调用模板化的 all_gather<STATE_GROUP_ALL_GATHER_INTO_TENSOR>,并将结果写入用户提供的输出张量(而非内核内部分配)。对应在 torch_extension_cpu.cpp 中注册为 sgl_kernel.shm_allgather_into_tensor

  3. 新增 shm_reduce_scatter_tensor:在 interface.cpp 中实现 shm_reduce_scatter_tensor 函数,调用新编写的 reduce_scatter_outer_loop(基于共享内存的 reduce-scatter 逻辑),仅支持 ReduceOp.SUM。在 shm.h 中声明该函数,并在 torch_extension_cpu.cpp 中注册。

  4. 扩展共享内存数据结构:在 shm.cpp 中为三个新操作添加双缓冲区指针 (allgather_buffer, allgather_into_tensor_buffer, reduce_scatter_buffer);增加 BUFFER2_OFFSET/BUFFER3_OFFSET/BUFFER4_OFFSET 宏计算偏移量,确保各操作缓冲区不重叠。

  5. 测试与 CI 注册:将 test/manual/cpu/test_comm.py 迁移至 test/registered/cpu/test_comm.py,新增 test_all_gather_into_tensortest_reduce_scatter_tensor 测试方法(对比 dist 标准实现输出),并通过 register_cpu_ci 注册到 CPU 基础 CI 套件。

文件 模块 状态 重要度
sgl-kernel/csrc/cpu/shm.cpp 内核实现 modified 7.81
test/registered/cpu/test_comm.py 测试 renamed 7.18
sgl-kernel/csrc/cpu/interface.cpp 接口层 modified 5.86
sgl-kernel/csrc/cpu/torch_extension_cpu.cpp 接口层 modified 5.17
sgl-kernel/csrc/cpu/shm.h 内核实现 modified 5.14

关键符号

shm_allgather_into_tensor shm_reduce_scatter_tensor all_gather (template with STATE_GROUP) reduce_scatter_outer_loop shm_initialize (modified states initialization)

关键源码片段

sgl-kernel/csrc/cpu/shm.cpp core-logic

核心实现文件,修改了状态枚举、workspace 结构、缓冲区定义和初始化,是避免竞态的关键。

// 枚举增加 reduce_scatter 状态,与 all_gather 原有状态共同构成完整状态集
enum coll_state {
  coll_begin = 0,
  coll_allreduce_naive__copy_in_done,
  coll_allreduce_naive__reduce_done,
  coll_alt1_allreduce_naive__copy_in_done,
  coll_alt2_allreduce_naive__copy_in_done,
  coll_alt1_allreduce_naive__reduce_done,
  coll_allgather_naive__copy_in_done,
  coll_alt1_allgather_naive__copy_in_done,
  coll_alt2_allgather_naive__copy_in_done,
  // 新增的 reduce_scatter 阶段状态
  coll_reduce_scatter_naive__copy_in_done,
  coll_reduce_scatter_naive__reduce_done,
  coll_alt1_reduce_scatter_naive__copy_in_done,
  coll_alt2_reduce_scatter_naive__copy_in_done,
};// workspace 结构:states 从 2 扩展到 5,buffer 按需增加
struct allreduce_workspace {
  // 5 个状态组分别对应:symmetric_allreduce, distributed_allreduce, all_gather, all_gather_into_tensor, reduce_scatter
  enum coll_state states[5];
  // 缓冲区布局:先两个 reduce 区,再三个 gather/scatter 区,每区均为双缓冲
  char buffer[
    2 * NAIVE_ALLREDUCE_THRESHOLD + // 对称 allreduce(小消息)
    2 * MAX_BUF_SIZE + // 分布式 allreduce(大消息)
    2 * MAX_BUF_SIZE + // allgather
    2 * MAX_BUF_SIZE + // allgather_into_tensor
    2 * MAX_BUF_SIZE // reduce_scatter
  ];
};// 初始化时使用带语义的常量索引,提高可读性和维护性
workspace_buf->states[STATE_GROUP_SYMMETRIC_ALLREDUCE] = coll_alt2_allreduce_naive__copy_in_done;
workspace_buf->states[STATE_GROUP_DISTRIBUTED_ALLREDUCE] = coll_begin;
// 新增状态组初始化为 coll_begin
for (int g = STATE_GROUP_ALL_GATHER; g <= STATE_GROUP_REDUCE_SCATTER; ++g) {
  workspace_buf->states[g] = coll_begin;
}
test/registered/cpu/test_comm.py rename-or-move

测试文件,新增两个测试函数并注册到 CI,验证内核正确性。

# 对比标准 dist.all_gather_into_tensor 的结果
@register_cpu_ci(est_time=30, suite="base-b-test-cpu")
def all_gather_into_tensor_fn(rank, world_size):
    for dtype in [torch.float32, torch.bfloat16, torch.float16]:
        tensor = torch.randn(2, 10, dtype=dtype)
        output_size = (tensor.size(0) * world_size,) + tensor.size()[1:]
        output_tensor = torch.empty(output_size, dtype=dtype)
        output_shm = torch.empty(output_size, dtype=dtype)
        # 使用标准分布式库作为参考
        dist.all_gather_into_tensor(output_tensor, tensor)
        # 调用 sgl 内核
        torch.ops.sgl_kernel.shm_allgather_into_tensor(output_shm, tensor)
        # 验证一致性
        torch.testing.assert_close(output_tensor, output_shm)# 对比标准 dist.reduce_scatter_tensor 的结果 
@register_cpu_ci(est_time=30, suite="base-b-test-cpu")
def reduce_scatter_tensor_fn(rank, world_size):
    op = dist.ReduceOp.SUM
    for dtype in [torch.float32, torch.bfloat16, torch.float16]:
        N, D = 4, 10
        tensor = torch.randn(world_size * N, D, dtype=dtype)
        output_tensor = torch.empty(N, D, dtype=dtype)
        output_shm = torch.empty_like(output_tensor)
        dist.reduce_scatter_tensor(output_tensor, tensor, op=op)
        torch.ops.sgl_kernel.shm_reduce_scatter_tensor(output_shm, tensor, op)
        torch.testing.assert_close(output_tensor, output_shm)class TestComm(CustomTestCase):
    def test_all_gather_into_tensor(self):
        self._spawn_and_check(all_gather_into_tensor_fn)
​
    def test_reduce_scatter_tensor(self):
        self._spawn_and_check(reduce_scatter_tensor_fn)

评论区精华

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

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

风险与影响

新增内核依赖共享内存同步,若缓冲区分配或偏移量计算错误可能导致越界访问或死锁。wait_buffer_state_until_2 中的忙等待机制在极端竞争下可能有性能抖动(CPU 场景可接受)。shm_reduce_scatter_tensor 仅支持 SUM 归约,使用其他 op 会触发断言失败。测试覆盖了三种数据类型和 2 rank 场景,但未覆盖多 rank(>2)或异常路径。

对用户:CPU 上的 DP attention 将获得专用通信内核,替代通用慢路径,预期提升性能和可扩展性。对系统:增加共享内存分配大小(每个操作额外 2 * MAX_BUF_SIZE),但通过双缓冲消除了操作间干扰。对团队:为后续添加更多 CPU collectives 提供了模板化模式,并建立了 CI 测试基线。

竞态条件修复 共享内存竞争 仅支持 SUM 归约

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论