故障排除

请确保您熟悉以下已知问题和有用的调试策略。

错误

NCCL 调用可能会返回各种返回代码。确保返回代码始终等于 ncclSuccess。如果任何调用失败并返回与 ncclSuccess 不同的值,则将 NCCL_DEBUG 设置为“WARN”将使 NCCL 在返回错误之前打印显式警告消息。

错误分为不同的类别。

  • ncclUnhandledCudaError 和 ncclSystemError 表示对外部库的调用失败。
  • ncclInvalidArgument 和 ncclInvalidUsage 表示在使用 NCCL 的应用程序中存在编程错误。

在任何一种情况下,请参阅 NCCL 警告消息以了解如何解决问题。

RAS

从 2.24 版本开始,NCCL 包括可靠性、可用性和可维护性 (RAS) 子系统,以帮助诊断和调试崩溃和挂起。

GPU Direct

NCCL 在很大程度上依赖 GPU Direct 进行 GPU 间通信。这指的是 GPU 使用直接点对点 PCI 消息直接与另一个设备(例如另一个 GPU 或网卡)通信的能力。

由于各种原因,直接点对点 PCI 消息可能会失败或性能不佳,例如缺少组件、虚拟机或容器配置错误或某些 BIOS 设置。

GPU 到 GPU 通信

为确保 GPU 到 GPU 通信正常工作,请查找 CUDA 示例中的 p2pBandwidthLatencyTest。

cd /usr/local/cuda/samples/1_Utilities/p2pBandwidthLatencyTest
sudo make
./p2pBandwidthLatencyTest

该测试应运行完成并报告 GPU 之间的良好性能。

另一个用于检查 GPU 到 GPU 性能的工具称为 nvbandwidth。可以从此处找到的代码和说明下载和构建它:https://github.com/NVIDIA/nvbandwidth

GPU 到 NIC 通信

GPU 还可以使用 GPU Direct RDMA (GDRDMA) 直接与网卡通信。这需要具有兼容的网卡和驱动程序,以及加载一个名为 nvidia-peermem 的额外内核模块。nvidia-peermem 模块现在随 CUDA 驱动程序一起提供,但必须在每次节点启动时加载,使用

sudo modprobe nvidia-peermem

GDRDMA 也可以通过结合使用最新 Linux 内核的 DMA-BUF 功能和开源 Nvidia GPU 驱动程序来启用。在这种情况下,NCCL 将自动检测并启用 DMA-BUF,因此 nvidia-peermem 模块将不是必需的。

PCI 访问控制服务 (ACS)

裸机系统

IO 虚拟化(也称为 VT-d 或 IOMMU)可能会干扰 GPU Direct,方法是将所有 PCI 点对点流量重定向到 CPU 根复合体,从而导致性能显着降低甚至挂起。您可以通过运行以下命令检查 PCI 桥上是否启用了 ACS

sudo lspci -vvv | grep ACSCtl

如果行显示“SrcValid+”,则可能已启用 ACS。查看 lspci 的完整输出,可以检查 PCI 桥是否启用了 ACS。

sudo lspci -vvv

如果 PCI 交换机启用了 ACS,则需要禁用它。在某些系统上,可以通过在 BIOS 中禁用 IO 虚拟化或 VT-d 来完成。对于 Broadcom PLX 设备,可以在操作系统中完成,但每次重启后都需要重新完成。

使用以下命令查找 PLX PCI 桥的 PCI 总线 ID

sudo lspci | grep PLX

接下来,使用 setpci 使用以下命令禁用 ACS,将 03:00.0 替换为每个 PCI 桥的 PCI 总线 ID。

sudo setpci -s 03:00.0 ECAP_ACS+0x6.w=0000

或者您可以使用类似于此的脚本

for BDF in `lspci -d "*:*:*" | awk '{print $1}'`; do
  # skip if it doesn't support ACS
  sudo setpci -v -s ${BDF} ECAP_ACS+0x6.w > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    continue
  fi
  sudo setpci -v -s ${BDF} ECAP_ACS+0x6.w=0000
done

虚拟机

虚拟机需要 ACS 才能运行,因此禁用 ACS 不是一种选择。为了在虚拟机内部以最大性能运行,需要在网络适配器中启用 ATS。

拓扑检测

NCCL 依赖 /sys 来发现 GPU 和网卡的 PCI 拓扑。在虚拟机或容器内运行时,请确保正确挂载 /sys。让 /sys 公开虚拟 PCI 拓扑可能会导致次优性能。

共享内存

为了在进程之间甚至进程的线程之间进行通信,NCCL 在 /dev/shm 中创建共享内存段。可能需要相应地增加操作系统对这些资源的限制。请参阅您系统的文档以获取详细信息。

如果共享内存不足,NCCL 将无法初始化。使用 NCCL_DEBUG=WARN 运行将显示类似于此的消息

NCCL WARN Error: failed to extend /dev/shm/nccl-03v824 to 4194660 bytes

Docker

特别是,Docker 容器默认限制共享和固定内存资源。在容器内使用 NCCL 时,请确保调整容器内的共享内存大小,例如通过向 docker 启动命令行添加以下参数

--shm-size=1g --ulimit memlock=-1

Systemd

当使用 mpirun 或 SLURM 运行作业时,systemd 可能会在检测到相应的用户未登录时删除共享内存中的文件,以尝试清理旧的临时文件。这可能会导致 NCCL 在初始化期间崩溃,并出现类似错误

NCCL WARN unlink shared memory /dev/shm/nccl-d5rTd0 failed, error: No such file or directory

鉴于 mpirun 和 SLURM 作业可以在节点上运行,而 systemd 不会将用户视为已登录,因此系统管理员需要禁用该清理机制,这可以通过 SLURM epilogue 脚本来执行。为此,需要在 /etc/systemd/logind.conf 中设置以下行

RemoveIPC=no

更新后,应使用以下命令重启守护进程

sudo systemctl restart systemd-logind

网络问题

IP 网络接口

NCCL 自动检测要用于节点间通信的网络接口。如果某些接口处于 UP 状态但无法在节点之间通信,则 NCCL 可能会尝试仍然使用它们,因此在初始化函数期间失败甚至挂起。

有关如何指定要使用的接口的信息,请参阅环境变量部分,特别是 NCCL_SOCKET_IFNAME 环境变量。

IP 端口

NCCL 打开 TCP 端口以将进程连接在一起并交换连接信息。要限制 NCCL 使用的端口范围,可以设置 Linux 内核的 net.ipv4.ip_local_port_range 属性。

此示例显示如何将 NCCL 端口限制为 50000-51000

echo 50000 51000 > /proc/sys/net/ipv4/ip_local_port_range

或者要使其永久生效,请在 /etc/sysctl.conf 中添加一行

echo "net.ipv4.ip_local_port_range = 50000 51000" >> /etc/sysctl.conf

限制端口范围对于在防火墙中打开相应的范围可能很有用,例如在 Google Cloud 上

gcloud compute --project=myproject firewall-rules create ncclnet0-ingress --direction=INGRESS --priority=1 --network=ncclnet --action=ALLOW --rules=tcp:50000-51000,22,1024-1039 --destination-ranges=0.0.0.0/0 --target-tags=ncclnet

InfiniBand

在 InfiniBand 上运行 NCCL 之前,运行低级 InfiniBand 测试(特别是 ib_write_bw 测试)可以帮助验证节点是否能够正常通信。

InfiniBand 常见的一个问题是库无法注册足够的固定内存。在这种情况下,您可能会看到类似以下的错误

NCCL WARN Call to ibv_create_qp failed

NCCL WARN Call to ibv_reg_mr failed

解决方案是删除用户对注册固定内存的限制。可以通过添加以下行来完成

* soft memlock unlimited
* hard memlock unlimited

/etc/security/limits.conf 配置文件或 Linux 发行版上的等效文件。

基于融合以太网的 RDMA (RoCE)

在 RoCE 上运行 NCCL 之前,运行低级 RDMA 测试(特别是 ib_write_bw 测试)可以帮助验证节点是否能够正常通信。

RoCE 常见的一个问题是为 RoCE v2 NIC 选择了不正确的 GID 索引。这可能会导致以下错误

NCCL WARN Call to ibv_modify_qp failed with error Invalid argument

在 NCCL 2.21 及更高版本中,GID 索引是动态选择的,但在早期版本中,用户需要运行

show_gids

然后将 NCCL_IB_GID_INDEX 设置为 RoCE v2 VER GID 的 GID INDEX。对于 NCCL 2.21 及更高版本,不应设置此环境变量。

用户可能还需要在使用基于 RoCE 的网络时设置 NCCL_IB_TC。有关应设置为的值,请参阅您的供应商文档。