hcomm:昇腾集群通信的底层原语

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 的 Send 和 Recv 原语来传输数据块。

cpp 复制代码
// 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 集合通信库

相关推荐
余槐i1 小时前
Ollama 长文档问答后半段全空:context 默认值与静默截断的代价
性能优化·大模型·api·rag·ollama
FBI HackerHarry浩2 小时前
Pytorch中 CPU tensor vs GPU tensor
人工智能·pytorch·python·深度学习
白山编程大哥2 小时前
把 AO 接回来:黑线和白底之间到底差了多少
交互
跟我学机器学习2 小时前
Agent记忆机制:短期记忆与长期记忆概览
人工智能·深度学习·语言模型·数据挖掘
明志数科3 小时前
机器人训练数据的结构性缺口:场景·视角·质量的三重错配分析
人工智能·深度学习·机器人
yunfanleo3 小时前
模型微调(Fine-tuning)详解:原理、Full/LoRA/QLoRA 三种方案对比与 PEFT 工程实践
人工智能·深度学习·机器学习·大模型·人工智能python
严谨的麻辣烫3 小时前
为什么 API 接口偶尔报错,重试一次又恢复了?从 HTTP 连接池到 Keep-Alive 排查
python·网络协议·tcp/ip·http·性能优化
用AI来创业吧3 小时前
企业官网搭建一般多久能上线:把工期拆成 7 段,算清哪段会拖
性能优化·自动化·安全威胁分析
老唐7773 小时前
(附代码)使用OpenCV和关键点检测计算瓶子角度
人工智能·深度学习·opencv·目标检测·计算机视觉·ai·transformer
Eyfcom3 小时前
〖实战〗快运系统 Oracle 性能优化:从“能用”到“扛住双11”的 Java + Spring Boot 实战
java·oracle·性能优化·快递管理系统