HCCL 管着 AllReduce、AllGather 这些高层集合通信操作。这些操作最终拆解成最基本的通信原语——Send、Recv、Broadcast。hcomm 就是负责这些底层通信原语的仓库。

HCCL 和 hcomm 的分工清晰:HCCL 负责通信算法(Ring AllReduce 怎么切分数据、树形 AllGather 怎么组织),hcomm 负责把这些算法翻译成硬件上的实际收发操作。


hcomm 与 HCCL 的关系

通信栈的分层:

应用层:torch.distributed.all_reduce
  ↓
通信库层:HCCL——通信算法实现
  ↓
通信算子层:hcomm——底层 Send/Recv 原语
  ↓
硬件层:HCCS 互联 / RoCE 网络

HCCL 的 AllReduce 拆解为 ReduceScatter + AllGather。其中 ReduceScatter 内部调用 hcomm 的 SendRecv 原语来传输数据块。

// HCCL 的 ReduceScatter 简化实现
// 内部调用 hcomm 原语
void ReduceScatter(float* send_buf, float* recv_buf, int count, int rank, int nranks) {
    // 切分数据
    int chunk_size = count / nranks;
    int recv_chunk = (rank - 1 + nranks) % nranks;
    int send_chunk = rank;
    
    for (int step = 0; step < nranks - 1; step++) {
        // hcomm 的发送和接收原语
        hcomm::Send(send_buf + send_chunk * chunk_size, chunk_size, next_rank);
        hcomm::Recv(temp_buf, chunk_size, prev_rank);
        
        // 在接收到的数据上做元素求和
        for (int i = 0; i < chunk_size; i++) {
            send_buf[send_chunk * chunk_size + i] += temp_buf[i];
        }
        
        send_chunk = (send_chunk - 1 + nranks) % nranks;
        recv_chunk = (recv_chunk - 1 + nranks) % nranks;
    }
}

HCCL 管"数据怎么切"和"每步传给谁",hcomm 管"怎么把数据发过去"和"怎么把数据接回来"。


Tensor 同步为什么会成为瓶颈

分布式训练中每步的通信量由模型大小决定。LLaMA-70B 的梯度 Tensor 约 140GB。Ring AllReduce 把 8 卡场景的每卡通信量降到约 35GB。

35GB 的传输在 HCCS(100GB/s)上需要约 350ms。训练一个 step 的前向+反向计算约 500ms。通信占了 40% 的时间。

hcomm 级别的 Send/Recv 延迟包括:

  1. DMA 准备。 hcomm 在发送前需要把数据从发送方的计算 Buffer 搬移到通信 Buffer——约 5-15μs
  2. 链路传输。 数据在 HCCS 链路上传输——跟数据量成正比
  3. DMA 完成。 接收方从通信 Buffer 搬回计算 Buffer——约 5-15μs

优化方向:hcomm 支持零拷贝路径——发送方直接读计算 Buffer 做 DMA 传输,不经过通信 Buffer。零拷贝适用于训练中的梯度同步(数据已经在显存中),省掉两次 Buffer 搬运。


昇腾通信链路解析

卡 0 向卡 1 发送数据的完整链路:

卡 0:
  hcomm::Send(buffer, size, rank=1)
    → 通信 Buffer 分配
    → DMA 从计算 Buffer → 通信 Buffer(如果走非零拷贝)
    → HCCS 链路传输启动
    → Doorbell 通知卡 1

HCCS 链路:
  数据从卡 0 的显存 → PCIe/HCCS → 卡 1 的显存

卡 1:
  HCCS 控制器收到 Doorbell 信号
    → DMA 从通信 Buffer → 计算 Buffer
    → 通知 hcomm::Recv 调用者"数据已就绪"

整个过程约 10-15μs 的固定开销 + 数据量 / 带宽的可变开销。


分布式推理中的通信

推理场景的通信模式跟训练不同。训练是 AllReduce(每张卡发数据给所有卡),推理是 AllGather(每张卡从所有卡收集计算分片)。

以 8 卡张量并行推理 LLaMA-13B 为例:

Attention 计算时每张卡持有 1/8 的 Head。
每张卡算完自己的 Attention 分片后,需要把所有分片拼起来得到完整的 Attention 输出。
  → AllGather 操作
  → 每张卡把本卡的分片广播给所有卡
  → 每张卡持有完整结果

AllGather 的通信量 = (n-1) × slice_size / n。Attention Head 分片大小 = B × n_heads × seq_len × head_dim / 8。Batch=1、n=4096 时单步约 4MB。8 卡 AllGather 的通信量约 28MB。

hcomm 在 AllGather 场景中支持 Ring 算法和 Tree 算法两种实现。Ring 适合小数据量(延迟低),Tree 适合大数据量(带宽高)。HCCL 根据数据量自动选择。

hcomm 的数据传输路径

hcomm 的 Send 操作涉及的数据路径:

  1. 发送方将数据从计算 Buffer 拷贝到通信 Buffer(如果是零拷贝模式则跳过)
  2. 通信 Buffer 的物理地址注册到 DMA 引擎
  3. DMA 引擎透过 HCCS 或 PCIe 将数据传输到接收方的通信 Buffer
  4. 接收方将数据从通信 Buffer 拷贝到计算 Buffer(零拷贝模式也跳过)

非零拷贝路径涉及 2 次显存拷贝,零拷贝路径 0 次。零拷贝的代价是需要额外的地址映射——通信双方需要预先注册显存段的访问权限。这个注册在通信域初始化时一次性完成。

hcomm 在推理场景中的使用

推理场景中的 hcomm 主要用于张量并行通信。LLaMA-13B 在 8 卡上做张量并行推理时,每步 Attention 计算需要跨卡 AllGather 结果。hcomm 的 AllGather 原语通过一条 hcomm::AllGather(send_buf, recv_buf, count, comm) 调用完成——内部自动拆解为 Ring 算法或 Tree 算法的 Send/Recv 序列。

参考仓库

hcomm 通信算子库

HCCL 集合通信库

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐