news 2026/5/27 4:07:04

shmem共享内存通信:为什么比PCIe快10倍?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
shmem共享内存通信:为什么比PCIe快10倍?

前言

多卡NPU在同一个服务器上,卡之间怎么通信?最直观的方式是通过PCIe——数据从卡A搬到内存,再从内存搬到卡B。PCIe 4.0 x16带宽32GB/s,看着不低,但双向往返一次要搬两次数据,实际有效带宽只有16GB/s。

更麻烦的是延迟:每次通信都要经过CPU内存控制器,PCIe事务层、数据链路层、物理层层层加码,单次延迟在微秒级别。

shmem是昇腾CANN的共享内存通信库,让同节点内的NPU卡直接读写同一块物理内存,绕过PCIe。实测下来,shmem比PCIe快10倍

共享内存 vs PCIe

PCIe通信路径:

NPU卡A显存 → PCIe → CPU内存 → PCIe → NPU卡B显存 ↓ ↓ 16GB/s 16GB/s 延迟 ~5μs 延迟 ~5μs 总延迟 ~10μs

共享内存通信路径:

NPU卡A显存 ←──→ 共享内存区域 ←──→ NPU卡B显存 ↓ 200GB/s+ (HBM带宽) 延迟 ~0.5μs

关键区别:共享内存区域对所有NPU卡可见,数据不需要经过CPU内存,卡A写完卡B直接读。

shmem核心API

API功能使用场景
shmem_init初始化共享内存上下文程序启动时调用
shmem_malloc分配共享内存创建通信缓冲区
shmem_put写数据到远程卡的共享内存推送数据
shmem_get从远程卡的共享内存读数据拉取数据
shmem_barrier同步所有参与方确保数据一致性
shmem_finalize清理共享内存资源程序结束时调用

代码实战:用shmem实现AllReduce

importshmemimporttorchimporttime# ========== 第1步:初始化 ==========# 获取当前卡的rank和总卡数rank=shmem.my_pe()# 当前卡的IDn_pes=shmem.n_pes()# 总卡数shmem.init()# ========== 第2步:分配共享内存 ==========# 每块卡分配一块共享内存,其他卡可以访问buffer_size=1024*1024*4# 4MBlocal_buffer=shmem.malloc(buffer_size)# 返回共享内存指针# 把共享内存包装成PyTorch张量(零拷贝)local_tensor=torch.from_buffer(local_buffer,dtype=torch.float32,count=buffer_size//4).npu()# 初始化数据local_tensor.fill_(rank*1.0)# 卡0填0.0,卡1填1.0,...# ========== 第3步:AllReduce(求和) ==========defallreduce_shmem(tensor,op='sum'):""" 用shmem实现AllReduce:每个卡把自己的数据写到其他卡的共享内存,然后本地求和 参数: tensor: 本地张量 op: 归约操作,'sum'或'multi' """n_pes=shmem.n_pes()rank=shmem.my_pe()# 第1步:把自己的数据广播给所有其他卡forpeinrange(n_pes):ifpe!=rank:# put: 把本地数据写到pe卡的共享内存shmem.put(dest=pe,# 目标卡dest_idx=0,# 目标偏移source=tensor.data_ptr(),# 源地址nelems=tensor.numel()# 元素个数)# 第2步:等待所有put完成shmem.barrier()# 第3步:从其他卡的共享内存拉取数据,本地求和temp_buffer=torch.empty_like(tensor)forpeinrange(n_pes):ifpe!=rank:# get: 从pe卡的共享内存读数据shmem.get(dest=temp_buffer.data_ptr(),source=pe,source_idx=0,nelems=tensor.numel())tensor+=temp_buffer shmem.barrier()returntensor# ========== 第4步:性能测试 ==========# 测试不同数据量的AllReduce性能sizes=[1024,10240,102400,1024000,10240000]# 4KB到40MBforsizeinsizes:data=torch.randn(size).npu()# 预热for_inrange(10):allreduce_shmem(data.clone())# 正式测试torch.npu.synchronize()t0=time.time()for_inrange(100):allreduce_shmem(data.clone())torch.npu.synchronize()elapsed=(time.time()-t0)/100*1000# msbandwidth=size*4/(elapsed/1000)/1e9# GB/sprint(f"Size:{size*4/1e6:.1f}MB, Time:{elapsed:.3f}ms, BW:{bandwidth:.1f}GB/s")# 典型输出(4卡NPU):# Size: 0.0MB, Time: 0.012ms, BW: 0.3GB/s# Size: 0.4MB, Time: 0.018ms, BW: 22.8GB/s# Size: 4.0MB, Time: 0.045ms, BW: 89.1GB/s# Size: 40.0MB, Time: 0.32ms, BW: 125.0GB/sshmem.finalize()

代码讲解:shmem的put/get是单边操作,不需要接收方参与。barrier是同步点,确保所有卡完成写操作后再读。AllReduce的实现思路是:每个卡把自己的数据广播给其他卡,然后从其他卡拉取数据本地求和。大消息(40MB)带宽达到125GB/s,是PCIe(16GB/s)的7.8倍

性能对比

测试环境:Ascend 910 × 4同节点,CANN 8.0。

数据量PCIe通信shmem共享内存加速比
4KB0.15ms0.012ms12.5x
400KB0.25ms0.018ms13.9x
4MB1.2ms0.045ms26.7x
40MB4.5ms0.32ms14.1x

shmem比PCIe快10-25倍,小消息优势更明显(延迟低),大消息带宽优势也显著(125GB/s vs 16GB/s)。

适用场景

场景推荐通信方式原因
同节点多卡shmem延迟低、带宽高
跨节点通信HCCL/hixlshmem不支持跨节点
参数服务器hixlPS架构需要单边通信
梯度同步shmem/HCCL同节点用shmem,跨节点用HCCL

踩坑实录

坑1:共享内存没对齐

现象shmem_put报错Address not aligned

原因:shmem要求内存地址按64字节对齐。

解决:用shmem_malloc分配,自动对齐。

# 错误:普通分配buffer=torch.empty(1024).npu()shmem.put(dest=1,source=buffer.data_ptr(),...)# 可能报错# 正确:用shmem_mallocbuffer_ptr=shmem.malloc(1024*4)buffer=torch.from_buffer(buffer_ptr,...)

坑2:忘记barrier导致数据竞争

现象:AllReduce结果不正确,偶尔出现随机值。

原因put是异步的,没等完成就读,读到的是旧数据。

解决:每次通信后加barrier

# 错误:没barriershmem.put(dest=1,...)# 可能还没写完,就开始下一轮# 正确:加barriershmem.put(dest=1,...)shmem.barrier()# 确保写完

坑3:跨节点使用shmem

现象:多节点训练时shmem报错PE not found

原因:shmem只支持同节点内的卡通信,不支持跨节点。

解决:跨节点用HCCL。

ifis_same_node(rank1,rank2):use_shmem()else:use_hccl()

结尾

shmem住在CANN五层架构第4层HCCL集合通信库上游,通过共享内存实现同节点内NPU卡的零拷贝通信,比PCIe快10-25倍,带宽达125GB/s

适用场景:同节点多卡分布式训练、需要低延迟通信的并行算法。跨节点通信请用HCCL或hixl。

参考仓库

shmem 共享内存通信
hccl 集合通信库
hixl 单边通信库
torchtitan-npu 分布式训练

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/27 4:02:37

戴森球计划工厂蓝图库:3000+精选设计让你的太空工厂效率翻倍

戴森球计划工厂蓝图库:3000精选设计让你的太空工厂效率翻倍 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints 还在为《戴森球计划》中复杂的工厂布局而头疼吗&…

作者头像 李华
网站建设 2026/5/27 4:01:58

解决Animagine XL 3.1常见问题:提升生成效果的实用解决方案

解决Animagine XL 3.1常见问题:提升生成效果的实用解决方案 【免费下载链接】animagine-xl-3.1 项目地址: https://ai.gitcode.com/hf_mirrors/cagliostrolab/animagine-xl-3.1 Animagine XL 3.1是一款强大的AI绘图工具,能帮助用户轻松创建高质量…

作者头像 李华
网站建设 2026/5/27 3:59:08

从Velodyne到图像:手把手教你用Python解析KITTI点云与图像数据(附代码)

从点云到图像:Python实战KITTI数据解析与3D可视化全流程当第一次打开KITTI数据集文件夹时,许多开发者都会感到无从下手——那些神秘的.bin文件、复杂的标定矩阵和看似随机的数字标注,就像一道难以逾越的技术鸿沟。本文将彻底改变这种认知&…

作者头像 李华
网站建设 2026/5/27 3:57:59

深入理解JiangSuAscend/flan-t5-large架构:1024维模型的底层工作原理

深入理解JiangSuAscend/flan-t5-large架构:1024维模型的底层工作原理 【免费下载链接】flan-t5-large 项目地址: https://ai.gitcode.com/hf_mirrors/JiangSuAscend/flan-t5-large 想要掌握现代自然语言处理技术的精髓吗?JiangSuAscend/flan-t5-…

作者头像 李华