4、NCCL Benchmarks:NCCL-Tests编译与运行,理解allreduce、allgather、reduce_scatter等操作
聊到NCCL性能,光看文档可不行。你得亲手跑一跑,才知道你的集群到底几斤几两。NCCL官方提供了一套基准测试工具,叫NCCL-Tests。说白了,它就是一把尺子,专门用来量你的GPU之间通信到底有多快。
我个人习惯,拿到一个新集群,第一件事就是编译NCCL-Tests,跑一轮allreduce。为什么?因为allreduce是最常用的集合通信操作,它的吞吐基本决定了你分布式训练的上限。
4.1 编译NCCL-Tests
编译这东西其实不复杂,但有几个坑。我曾经在一个老旧的CentOS系统上折腾了半天,最后发现是CUDA路径没配对。
先拉代码:
git clone https://github.com/NVIDIA/nccl-tests.git
cd nccl-tests
然后编译。这里要注意,你得指定CUDA的安装路径。如果你机器上装了多个CUDA版本,千万别搞混了。
make CUDA_HOME=/usr/local/cuda-12.1 NCCL_HOME=/usr/local/nccl
嗯,这里有个小技巧。如果你用的是NVIDIA的官方容器,比如NGC的PyTorch镜像,里面已经预装了NCCL。这时候你直接make就行,它会自动检测到环境变量。
编译成功后,你会看到一堆可执行文件:
all_reduce_perf— 测allreduce的all_gather_perf— 测allgather的reduce_scatter_perf— 测reduce_scatter的- 还有broadcast、reduce等等,但最常用的就是上面三个
make -j 并行编译,能省不少时间。但如果你内存不大,比如只有16GB,那还是老老实实单线程吧,不然容易OOM。
4.2 运行allreduce测试
编译完了,咱们先跑个最简单的allreduce。命令长这样:
./all_reduce_perf -b 8 -e 128M -f 2 -g 8
参数解释一下:
-b 8:起始数据量,8字节-e 128M:结束数据量,128MB-f 2:每次翻倍,也就是8、16、32...一直到128M-g 8:用8张GPU
跑起来之后,你会看到类似这样的输出:
# nThread 1 nGpus 1 minBytes 8 maxBytes 134217728 step: 2(factor)
#
# size time algbw busbw
# (B) (usec) (GB/s) (GB/s)
8 12.3 0.65 1.22
16 12.5 1.28 2.40
32 12.6 2.54 4.76
...
134217728 1234.5 108.72 203.85
这里我重点说一下busbw这一列。它代表的是总线带宽,也就是实际有效带宽。你想想看,allreduce操作里,每个GPU既要发数据又要收数据,所以实际吞吐会比algbw高一些。我个人习惯,主要看busbw,因为它更接近硬件极限。
4.3 理解allgather和reduce_scatter
跑完allreduce,咱们再看看另外两个操作。它们仨其实是一家人,在Ring算法里经常配合使用。
allgather:每个GPU把自己的数据块广播给所有人。结果就是,每个GPU都拥有了完整的数据集。
./all_gather_perf -b 8 -e 128M -f 2 -g 8
reduce_scatter:反过来,每个GPU只保留一部分数据的规约结果。比如8张卡,每张卡只保留1/8的最终结果。
./reduce_scatter_perf -b 8 -e 128M -f 2 -g 8
你可能会问,这三个操作有啥关系?我画个图你就明白了。
你看,AllReduce其实可以拆成两步:先ReduceScatter,再AllGather。这个分解在Ring算法里特别有用。我当年调优的时候,就是通过分别测这两个子操作的性能,定位到了某个节点上的PCIe带宽瓶颈。
4.4 多节点测试
单机8卡测完了,咱们得看看多机的情况。多节点测试需要用到mpirun:
mpirun -np 16 -hostfile hostfile ./all_reduce_perf -b 8 -e 128M -f 2 -g 8
这里-np 16表示16个进程,每个节点8张卡,那就是2个节点。hostfile里写上节点IP或主机名。
4.5 常见问题与调优思路
跑完测试,你可能会遇到一些奇怪的现象。我列几个常见的:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 小数据量带宽低 | 通信开销占比大 | 尝试NCCL_ALGO=Ring,或者增大batch size |
| 大数据量带宽上不去 | NVLink或IB带宽瓶颈 | 检查拓扑,确认是否跨Socket |
| 多节点性能差 | 网络拥塞或路由问题 | 设置NCCL_NET_GDR_LEVEL,尝试不同网卡绑定策略 |
| 结果不稳定 | CPU频率波动或散热问题 | 锁定CPU频率,检查GPU温度 |
嗯,说到调优,我有个习惯。每次跑测试前,先看一眼nvidia-smi topo -m的输出,确认GPU拓扑。你想想看,如果两张卡不在同一个PCIe Switch下,它们之间的通信就要绕路,带宽自然上不去。
NCCL_P2P_DISABLE=1强制走NVLink,问题就解决了。
最后,别忘了保存测试结果。我一般会把输出重定向到文件,方便后续对比:
./all_reduce_perf -b 8 -e 128M -f 2 -g 8 | tee allreduce_8gpu.log
这样,下次改了什么配置,一对比就知道效果如何。说白了,性能调优就是个不断测量、分析、调整的循环。NCCL-Tests就是你手里最趁手的工具。
想要更多资料,联系可可