all_reduce_perf 的带宽偏低时,先固定消息大小、rank 数、GPU 拓扑和测量方式,再判断瓶颈出在节点内部还是节点之间。同一张表里还有 in-place 与 out-of-place 两组结果,混着比较容易误判。

资料核对于 2026 年 11 月 8 日。本文命令依据 NVIDIA 官方 nccl-tests 与 NCCL 文档,已检查 shell 语法和日志解析计算。当前验证环境只有一张 GPU,未执行多卡或跨节点吞吐测试。
下载 NCCL 日志汇总脚本,用于把默认输出中的两组指标分别整理为 CSV,并检查正确性错误与公式一致性。
先读懂 time、algbw 与 busbw
algbw 按单次操作的数据大小除以耗时计算。对 AllReduce,nccl-tests 使用总 rank 数 n 修正得到 busbw,修正因子为 2 × (n − 1) ÷ n。rank 数为所有进程、线程和每线程 GPU 数的乘积,不能直接填节点数。定义见官方性能口径。
| 字段 | 解读方式 | 比较前确认 |
|---|---|---|
| time | 一次操作的耗时 | 以输出表头为准,本文脚本接受微秒 us |
| algbw | size ÷ time,以 GB/s 表示 | GB 使用十进制,输入 size 列为实际字节数 |
| busbw | AllReduce 的归一化带宽 | 这是集体通信换算指标,不等于某一网口的计数器读数 |
| #wrong | 启用校验时发现的错误数量 | 先确认正确性,再讨论性能 |
下面只演算单位换算:假设 8 个 ranks,size 为 8,388,608 字节,time 为 1,000 us,则 algbw 约 8.39 GB/s,busbw 约 14.68 GB/s。这组假设数值也用于验证下载脚本的解析逻辑。
小消息更适合观察固定开销,大消息更适合看带宽平台。至少记录相同规模下的连续多个大小,保留每轮原始输出,避免只挑一个峰值。多节点算法可能同时使用节点内与节点间链路,判断网卡利用率时还要结合实际流量和拓扑。
准备可重复的单机基线
在 Linux 测试环境确认 CUDA、NCCL 头文件与运行库、GPU 数量及所用 nccl-tests commit。以下路径需要按实际安装位置修改,先确认动态链接的库符合预期。
1 2 3 4 5 6 7 | git clone https://github.com/NVIDIA/nccl-tests.git cd nccl-tests git rev-parse HEAD make -j4 CUDA_HOME=/usr/local/cuda NCCL_HOME=/opt/nccl ldd ./build/all_reduce_perf | grep nccl nvidia-smi -L nvidia-smi topo -m |
用实际可见的两张 GPU 建立基线,显式开启正确性检查并保存日志。-b 和 -e 控制消息区间,-f 2 每次翻倍,-w 为预热次数,-n 为计时迭代次数。其他参数和支持版本见nccl-tests README。
1 2 3 4 5 6 7 8 | set -o pipefail export LD_LIBRARY_PATH="/opt/nccl/lib:/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}" mkdir -p logs for rep in 1 2 3; do CUDA_VISIBLE_DEVICES=0,1 \ ./build/all_reduce_perf -b 8 -e 128M -f 2 -g 2 -w 5 -n 20 -c 1 \ | tee "logs/single-node-2gpu-r${rep}.log" done |
这里总 rank 数为 2。需要扩大消息时先估计每个 rank 的缓冲区及其他显存占用。扩大到更多 GPU 后,重新记录拓扑与 rank 数。in-place 和 out-of-place 各自跨轮比较,保留所有校验结果。
单机慢时,从拓扑和 GPU P2P 开始
先对照 nvidia-smi topo -m 的 GPU 配对,比较同一交换机、跨 PCIe 根复合体或跨 NUMA 的差异。检查容器中的 /sys 是否能反映实际设备拓扑,CPU 亲和性是否与机器配置相符,再测试具体 GPU 对的 P2P 能力。
ACS、IOMMU、虚拟化方式和驱动可能影响直连路径;裸机与虚拟机的要求不同,确认原因后再安排系统层调整。GPU 到网卡的 RDMA 既可能通过 nvidia-peermem,也可能通过受支持的 DMA-BUF 路径启用,因此单凭某个模块没加载还不能确定故障。检查方法见NVIDIA GPU 排障指南。
再扩展到两节点 MPI 对照
两台节点应具备可用的 MPI 启动环境、匹配的 NCCL/CUDA 运行条件,以及相同绝对路径下的测试程序。先确认单节点基线,再测试两节点,便于识别新增的网络因素。以下使用 Open MPI 的参数形式,每节点两个进程、每进程一张卡。
1 2 | make -j4 MPI=1 NAME_SUFFIX=_mpi \ MPI_HOME=/opt/mpi CUDA_HOME=/usr/local/cuda NCCL_HOME=/opt/nccl |
创建 hosts 文件,将主机名换成实际节点。
1 2 | node-a slots=2 node-b slots=2 |
1 2 3 4 5 6 7 8 9 | export NCCL_DEBUG=INFO export NCCL_DEBUG_SUBSYS=INIT,NET,GRAPH export NCCL_DEBUG_FILE='/tmp/nccl.%h.%p.log' export LD_LIBRARY_PATH="/opt/nccl/lib:/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}" mpirun -np 4 --hostfile hosts \ -x PATH -x LD_LIBRARY_PATH -x NCCL_DEBUG \ -x NCCL_DEBUG_SUBSYS -x NCCL_DEBUG_FILE \ /absolute/path/nccl-tests/build/all_reduce_perf_mpi \ -b 8 -e 128M -f 2 -g 1 -w 5 -n 20 -c 1 |
总 rank 数为 4。不要同时把进程数和每进程 GPU 数都乘成全机卡数。日志文件中的 %h、%p 分别展开主机与进程信息,便于区分各节点记录。收集日志时检查实际网络后端、网卡/HCA、GPU 与 NIC 的距离,以及是否出现预期外的回退。
用单变量对照定位网络问题
| 观察 | 下一组对照 | 保留证据 |
|---|---|---|
| 单机正常,跨机变慢 | 检查节点间链路和实际网络后端,比较小消息与大消息 | NCCL NET 日志、网卡计数器、消息大小 |
| 只有部分 GPU 配对慢 | 按 GPU/NIC 与 NUMA 拓扑分组复测 | GPU UUID、拓扑、CPU 绑定 |
| 卡数增多后波动变大 | 固定节点与消息大小,逐级增加 ranks,检查共享链路 | 每轮原始结果、负载时间窗 |
| 带宽正常但训练仍慢 | 检查应用的通信粒度、同步频率和计算通信重叠 | 应用 profiler 与对应批次配置 |
NCCL_SOCKET_IFNAME 用于 socket 接口选择,RDMA HCA 的选择还需看 NCCL_IB_HCA 与实际后端。先从日志确认接口,再在单次测试中限制范围复测。NCCL_ALGO、NCCL_PROTO 等调优项应逐项比较,并记录恢复默认配置后的结果。变量定义与调试配置的适用范围见官方环境变量参考。
整理成可对比的报告
下载脚本只处理默认的 13 列 all_reduce_perf 数值行,输出两种内存模式各自的 CSV 行。命令中的 ranks 应填该次测试的总数,time-unit 必须与表头一致。新增列或更改单位的日志需先调整解析口径。
1 2 | python nccl_report.py logs/single-node-2gpu-r1.log \ --ranks 2 --time-unit us --output single-node-r1.csv |
脚本遇到 #wrong 非零或数值与公式不一致会以非零状态退出。先检查这些问题,再比较同一消息大小与内存模式的三轮波动。报告同时保存硬件、驱动、NCCL 版本、测试 commit、命令和环境变量,方便复查。
通信原理可接着阅读All-Reduce、All-Gather 与 Reduce-Scatter 的执行逻辑,算法选择背景见NCCL Ring 与 Tree 对比。
汤不热吧