3. 硬件环境摸底
做分布式训练,最怕什么?
我最怕的是:代码写好了,集群跑起来了,结果性能只有理论值的30%。
你查日志、调参数、改代码,折腾两天,最后发现——是硬件拓扑没摸清。GPU之间走的是PCIe而不是NVLink,跨节点通信走了慢路径。嗯,这种坑我踩过不止一次。
所以这一章,咱们就聊聊怎么给硬件环境「摸底」。说白了,就是搞清楚你的机器到底长什么样,GPU怎么连的,CPU和内存带宽够不够,网络是不是瓶颈。
3.1 GPU拓扑结构:NVLink vs PCIe
先问个问题:你机器里有8张卡,它们之间怎么通信?
答案取决于拓扑。我见过不少同学,上来就调大batch size,结果发现通信开销比计算还大。为什么?因为GPU之间走的是PCIe,带宽只有NVLink的十分之一。
3.1.1 用 nvidia-smi 看拓扑
最直接的工具就是 nvidia-smi。但大多数人只用它看显存和温度,其实它还能看拓扑。
# 查看GPU之间的连接关系
nvidia-smi topo -m
输出大概长这样:
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
GPU0 X NV2 NV2 NV2 PHB PHB PHB PHB
GPU1 NV2 X NV2 NV2 PHB PHB PHB PHB
GPU2 NV2 NV2 X NV2 PHB PHB PHB PHB
GPU3 NV2 NV2 NV2 X PHB PHB PHB PHB
GPU4 PHB PHB PHB PHB X NV2 NV2 NV2
GPU5 PHB PHB PHB PHB NV2 X NV2 NV2
GPU6 PHB PHB PHB PHB NV2 NV2 X NV2
GPU7 PHB PHB PHB PHB NV2 NV2 NV2 X
这里 NV2 表示NVLink 2.0连接,PHB 表示走PCIe。你看,GPU0-3之间是NVLink,GPU4-7之间也是NVLink,但两组之间只能走PCIe。
关键点:分布式训练中,AllReduce通信尽量在NVLink域内完成。跨域通信会经过PCIe,带宽骤降。
3.1.2 我踩过的坑
有一次,我在一台8卡机器上跑模型并行。我把模型切了两半,分别放在GPU0和GPU4上。结果每次前向传播都要等很久。
查了半天,才发现GPU0和GPU4之间走的是PCIe。我赶紧把模型切到GPU0和GPU1上,速度直接翻倍。
所以我的习惯是:跑任何分布式任务之前,先跑一遍 nvidia-smi topo -m,把拓扑图画出来。
3.2 CPU与内存带宽
GPU再快,数据也得从CPU内存搬过去。如果CPU内存带宽不够,GPU就得干等着。
3.2.1 用 lstopo 看CPU拓扑
lstopo 是hwloc工具包里的一个命令。它能画出CPU的NUMA节点、缓存层级、内存控制器位置。
# 安装hwloc
sudo apt-get install hwloc
# 查看CPU拓扑
lstopo
输出是一张图(或者文本)。你会看到:
- 有几个NUMA节点
- 每个NUMA节点下有哪些CPU核心
- 内存控制器挂在哪个节点上
- PCIe设备(包括GPU)连在哪个节点上
小技巧:如果GPU和CPU不在同一个NUMA节点,数据拷贝会有额外延迟。我一般用 numactl --membind 把进程绑定到GPU所在的NUMA节点。
3.2.2 实测内存带宽
光看拓扑不够,还得测实际带宽。我常用 stream 基准测试:
# 下载编译stream
wget https://www.cs.virginia.edu/stream/FTP/Code/stream.c
gcc -O3 -fopenmp -DSTREAM_ARRAY_SIZE=200000000 -DNTIMES=20 stream.c -o stream
# 运行
./stream
输出会告诉你:
- Copy带宽
- Scale带宽
- Add带宽
- Triad带宽
我遇到过一台机器,理论带宽是200GB/s,实测只有120GB/s。查了半天,发现是BIOS里内存频率没配好。嗯,这种硬件配置问题,工具一测就现原形。
3.3 网络互联:IB vs RoCE
跨节点训练,网络是命门。你想想看,8台机器,每台8卡,一共64张卡做AllReduce。如果网络带宽不够,通信时间比计算时间还长。
3.3.1 用 ibstatus 看IB网络
如果你的集群用了InfiniBand:
# 查看IB设备状态
ibstatus
输出:
Infiniband device 'mlx5_0' port 1 status:
state: ACTIVE
physical state: LINK_UP
rate: 200 Gb/sec (4X HDR)
这里 rate: 200 Gb/sec 就是单端口带宽。HDR是200Gbps,EDR是100Gbps,FDR是56Gbps。
3.3.2 用 ethtool 看RoCE
如果用的是RoCE(RDMA over Converged Ethernet):
# 查看网卡速率
ethtool enp175s0 | grep Speed
# 输出
Speed: 100000Mb/s
100000Mb/s = 100Gbps。但注意,这是链路层速率,实际有效带宽要低一些。
注意:RoCE对网络质量要求很高。我曾经遇到丢包率0.1%,结果训练速度直接腰斩。所以用RoCE之前,一定要测一下 iperf 和 ib_write_bw。
3.3.3 实测网络带宽
我习惯用 ib_write_bw 测点对点带宽:
# 在服务端
ib_write_bw -d mlx5_0
# 在客户端
ib_write_bw -d mlx5_0 192.168.1.1
输出会显示不同消息大小下的带宽。重点关注大消息(1MB以上)的带宽,因为分布式训练中梯度同步都是大消息。
3.4 一张图总结:硬件摸底流程
下面这张图,是我自己总结的硬件摸底流程。每次拿到新集群,我都会按这个步骤走一遍。
3.5 实战建议
最后,给你几个我自己的实战建议:
- 先摸底,再调参。我见过太多人上来就调学习率、调batch size,结果硬件瓶颈都没发现。
- 把摸底结果写下来。我习惯在每台机器上跑一遍
nvidia-smi topo -m和lstopo,把结果截图保存。这样出问题时能快速定位。 - 网络带宽要留余量。理论带宽和实际带宽之间,通常有20%-30%的差距。别把理论值当上限。
- 跨节点通信,优先走IB。如果集群同时有IB和RoCE,IB的稳定性和延迟都更好。我踩过RoCE的坑,丢包率一高,训练直接崩。
一句话总结:硬件摸底不是一次性的工作。每次集群变更、每次新任务启动,都值得重新摸底。你想想看,花10分钟摸底,可能省下你一天调参的时间。