跳到主要内容

故障排除

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

错误

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

错误分为不同的类别。

  • ncclUnhandledCudaErrorncclSystemError 表示对外部库的调用失败。
  • ncclInvalidArgumentncclInvalidUsage 表示在使用 NCCL 的应用程序中存在编程错误。

无论哪种情况,都应参考 NCCL 警告消息以了解如何解决问题。

GPU Direct

NCCL 在 GPU 之间的通信中大量依赖 GPU Direct。这是指 GPU 直接与另一个设备(如另一个 GPU 或网络适配器)进行通信,使用直接的点对点的 PCI 消息。

直接的点对点 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 与网络适配器直接通信。这需要兼容的网络适配器和驱动程序,以及加载一个名为 nvidia-peermem 的额外内核模块。nvidia-peermem 模块现已随 CUDA 驱动程序提供,但必须在每次节点启动时加载:

sudo modprobe nvidia-peermem

PCI 访问控制服务 (ACS)

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

sudo lspci -vvv | grep ACSCtl

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

sudo lspci -vvv

如果 PCI 开关已启用 ACS,则需要禁用它。在某些系统上,可以通过禁用 IO 虚拟化或 VT-d 从 BIOS 上做到这一点。对于 Broadcom PLX 设备,可以从操作系统中禁用它,但需要在每次重启后再次禁用。

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

sudo lspci | grep PLX

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

sudo setpci -s 03:00.0 f2a.w = 0000

拓扑检测

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会自动检测用于节点间通信的网络接口。如果某些接口处于启动状态,但无法在节点之间通信,则NCCL可能会尝试使用它们,从而在初始化函数期间失败或甚至挂起。

有关如何指定要使用的接口的信息,请参阅NCCL Knobs部分,特别是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

或者可以将其设置为永久生效,向/set/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

解决方案是删除注册固定内存的用户限制。可以通过向/etc/security/limits.conf配置文件或您的Linux发行版上的等效文件添加以下行来完成:

* soft memlock unlimited
* hard memlock unlimited