Runbook: NCCL socket fallback despite InfiniBand/RoCE present¶
Scope: diagnose and fix NCCL choosing TCP sockets, or running IB/RoCE without GPUDirect RDMA, on a node where RDMA hardware is present and expected to be used. Distinct from a full hang: the job keeps running, just one to two orders of magnitude slower, with no crash and no XID.
Run this when a job is progressing but far slower than its established baseline,
nccl-testsbusbw sits well under the fabric's line rate, and there is no collective timeout. Severity: job-degraded, not job-down. Because nothing crashes and nothing times out, this fails silently: a training run can burn a full day at a fraction of expected throughput before anyone notices. If step time has actually gone to infinity and a collective never returns, this is the wrong page; go to the NCCL-hang runbook.Reference templates on real APIs; pin versions and validate before production use. Nothing here was hardware-tested.
Fabric background is in networking fabric and RDMA and RoCE performance tuning; the collective algorithms and the busbw/algbw numbers are in NCCL collectives & algorithms; the Kubernetes device/network plumbing a container needs for RDMA is in the NicClusterPolicy manifest; the live monitoring tools are in diagnostics tools and nvidia-smi reference; an ACS misconfiguration blocking the GPUDirect path is the PCIe/P2P bandwidth-regression runbook.
Trigger¶
- Throughput or step time far below the established baseline, but the job is progressing: no exit, no XID, no collective timeout.
nccl-testsbusbw sits well under the topology's line rate (fabric bring-up and benchmarking, recipe: fabric validation) for a link that should carry tens of GB/s (IB/RoCE) or more.NCCL_DEBUG=INFOshowsNET/Socketwhere an IB/RoCE transport was expected, or shows an IB/RoCE transport with noGDRDMAtag on the channel.- GPU
smutilisation is low relative to a compute/comm-bound step while a host CPU core is pegged during the collective: the classic fingerprint of NCCL staging data through the CPU instead of DMA'ing GPU-to-GPU.1 - Symptom appears freshly after: a new node or container image, a Kubernetes manifest change, a driver/OFED/NCCL upgrade, or ACS re-enabled by a BIOS reset.
Pre-checks¶
- Confirm it is a fallback, not a hang. The job must be making progress, just slowly. A full stall (step time to infinity, collective never returns) is the NCCL-hang runbook, not this one.
- Confirm the hardware is actually RDMA-capable on this node. GPUDirect RDMA needs a Tesla/data-center-class GPU and an RDMA-capable NIC; a workstation/consumer card with no such NIC path is expected to run over sockets, not a fallback to diagnose.
- Confirm the IB/RoCE port is Active, not just cabled:
- Record the established busbw baseline for this exact topology and message size before changing anything; without a recorded number, "slow" is a guess (fabric bring-up and benchmarking, MFU regression runbook).
Flow¶
flowchart TB
A["Job runs but busbw far below baseline, no hang"] --> B["NCCL_DEBUG=INFO: read the NET line"]
B -->|"NET/Socket"| C["No RDMA device usable at all"]
B -->|"NET/IB or NET/RoCE, no GDRDMA"| D["RDMA transport up, GPU-direct disabled"]
C --> E["Check container device access, HCA filter, IB_DISABLE, verbs lib, subnet manager"]
D --> F["Check ACS, GID/container mismatch, GDR level, nvidia_peermem or DMA-BUF"]
E --> G["Fix + relaunch"]
F --> G
G --> H["Verify: nccl-tests busbw + dmon"]
H -->|"pass"| I["Return to service"]
H -->|"still degraded"| B
Procedure¶
- Read which transport NCCL is actually using right now. Relaunch (or tail live logs from) the job with debug scoped to init and net, and grep the channel lines: Three outcomes, each pointing at a different branch below:
Channel 00 : 1[...] -> 0[...] [send] via NET/IB/0/GDRDMA(or the RoCE equivalent): the fast path is engaged. If busbw is still low, the transport is not the problem; re-check the baseline and message size, or suspect a degraded link (fabric bring-up and benchmarking).NET/Socket(orusing Ethernet interface eth0with no IB/RoCE line at all): no RDMA device is usable by this process at all. Go to step 5.-
An IB/RoCE line with no
GDRDMAsuffix, or an explicitGPU Direct RDMA Disabled for HCA ...message: the RDMA transport itself came up, but GPUDirect is disabled, so the NIC and GPU are staging through host memory instead of DMA'ing directly. Go to step 6. -
Read
Read the tail (largest message size). As a rough triage signature, not a hard threshold: a full socket fallback typically lands in the low single-digit GB/s or below (the book's worked example: a 400 MB all-reduce on 800 Gb/s / 100 GB/s hardware runs at roughly 2 GB/s over a CPU-bound Gloo-style path versus roughly 100 GB/s, line rate, with GPUDirect RDMA engaged);1 a GDR-disabled path (RDMA up, host-staged) usually sits meaningfully below line rate but above that socket-fallback floor, since it still moves data over the RDMA fabric, just via an extra host-memory copy. Treat both as directional; record and use your own measured fleet baseline rather than a borrowed number (recipe: fabric validation).busbwagainst the topology's line rate, notalgbw.busbwapplies the collective's correction factor (for AllReduce,algbw * 2*(n-1)/n) so the figure is comparable to hardware peak independent of rank count.2 -
Corroborate with
nvidia-smi dmon, paired with a host CPU monitor.dmonreports the GPU side only (SM utilisation, PCIe Rx/Tx throughput); it has no host-CPU column, so pair it with a host tool to see the full fallback signature:3During a healthy GPUDirect collective,ssh "$NODE" 'nvidia-smi dmon -s put -d 1' # power/temp, utilisation (incl. sm%), PCIe throughput, 1s ssh "$NODE" 'mpstat -P ALL 1' # per-core host CPU, alongside dmonsmtracks the compute/comm-bound step andt(PCIe Rx/Tx, MB/s) reflects real DMA traffic. In a socket (or GDR-disabled) fallback,smdrops or flatlines low relative to that baseline while one or more host cores inmpstatsit pegged near 100%, the NCCL socket transport doing the copy on the CPU instead of the GPU DMA'ing directly.1 -
Confirm the port and subnet manager are actually healthy, since a down port or an unconverged fabric can itself present as "no usable IB device" (step 1's
NET/Socketbranch):ssh "$NODE" 'ibstat | grep -E "State:|Physical state:"' # expect Active / LinkUp ssh "$NODE" 'echo "verbose status" | nc localhost 28028' # NCCL RAS, if enabled (see the NCCL-hang runbook)DownorPollingphysical state means no subnet manager has converged on this port; that is a fabric fault, not a container/config problem, escalate to fabric bring-up and benchmarking rather than continuing here. -
Work the "no RDMA device usable" checklist (step 1 showed
NET/Socket, no IB/RoCE line at all): - Container/pod has no device access. The process needs
/dev/infiniband(or the RoCE equivalent) inside the container. On Kubernetes this needs both the RDMA device-plugin resource and the secondary network attachment; either alone is not enough, the resource without an attached interface yields no verbs handle with an IP, the interface without the resource yields no verbs handle at all (the NicClusterPolicy manifest): NCCL_IB_DISABLE=1set somewhere in the job's env (often copied in from a laptop/dev config and never removed). Grep the launch environment for it explicitly.NCCL_IB_HCAfilters out every real device. Compare the filter against what the host/container actually exposes:- Verbs libraries missing from the container image.
ibv_devices/ibv_devinfofailing or absent (not just empty) meanslibibverbs/rdma-corewas never installed in the image; NCCL's IB plugin cannot even attempt the fast path. IPC_LOCKcapability ormemlockulimit missing. Verbs need to pin memory; withoutIPC_LOCK(Kubernetes) or an unlimitedmemlock(bare container), registration fails and NCCL falls back:-
Port down / subnet manager not converged: covered in step 4 above; this is a fabric fault, not a config fix.
-
Work the "GPUDirect disabled" checklist (step 1 showed an IB/RoCE line with no
GDRDMA): - ACS P2P Request Redirect on the NIC-to-GPU PCIe path forces the transfer up through the Root Complex instead of straight across, blocking GPUDirect entirely even though the RDMA transport itself is healthy. Reuse the redirect-bit check and fix from the PCIe/P2P bandwidth-regression runbook:
Any bridge printing a
ssh "$NODE" "sudo lspci -vvv 2>/dev/null | grep -E 'ReqRedir\+|CmpltRedir\+|UpstreamFwd\+|SrcValid\+'"+flag needs the ACS-disable service. - GID mismatch between container and host (RoCE). A container that sees a different GID table than the host blocks GPUDirect registration and forces a CPU-driven RDMA copy instead of true GPU RDMA:4
NCCL_NET_GDR_LEVELset too restrictive for the actual NIC-to-GPU PCIe distance on this node. Values, increasing permitted distance:LOC,PIX,PXB,PHB,SYS. Leave it auto-selected unless you have measured the correct value for this topology; a hand-setPIXon a node where the NIC and GPU sit two PCIe switches apart disables GDR outright.nvidia_peermemnot loaded (legacy path) or the DMA-BUF prerequisites unmet (Open Kernel Module driver, CUDA >= 11.7, Turing-or-newer data-center GPU, kernel >= 5.12):5-
NCCL/OFED/driver version mismatch after an upgrade on only some nodes. Compare across the job's node set; a stale OFED on one rank can silently disable GDR for the pair even when the rest of the fleet is fine.
-
Fix, then relaunch the job. Do not declare it fixed on the config change alone; every fix here is confirmed by the same transport line and a re-measured
busbwin Verification below.
Verification¶
NCCL_DEBUG=INFOnow showsNET/IB/.../GDRDMA(or the intended RoCE equivalent) on every channel, notNET/Socketand not an IB/RoCE line missingGDRDMA.nccl-testsbusbw at the large-message tail returns to the fleet's recorded baseline for this topology, not just "better than before":nvidia-smi dmonshows the healthy pattern:smutilisation consistent with a compute/comm-bound step and PCIetthroughput consistent with real DMA traffic, with the host CPU (mpstat) no longer pegged during the collective.- The job's step time returns to its established baseline (observability).
Rollback¶
A silent fallback is not a change to revert; recovery is making sure the fix sticks and the fast path stays proven:
- Bake the fix into the launch template, manifest, or image, not a one-off env override on this run. A
NCCL_IB_HCAcorrection, anIPC_LOCKcapability, or a NicClusterPolicy fix that only lives in this job's command line regresses on the very next launch (SRE and MLOps practices). - If an ACS fix was applied, confirm it is the managed boot-time service, not a manual
setpci, so it survives the next reboot (the ACS-disable service). - If the root cause was a subnet manager or port fault (step 4), that is a fabric issue, not a job config issue; hand off to fabric bring-up and benchmarking and keep the node out of the pool until it is proven, not just "probably fine now."
- If nothing here resolves it and busbw stays low with a clean transport line, the fabric itself may be degraded (a bad cable, an asymmetric link); escalate to fabric bring-up and benchmarking rather than continuing to iterate on NCCL env vars.
Related runbooks¶
- the NCCL-hang runbook: the full-stall counterpart, when the job stops making progress entirely rather than just running slow.
- the PCIe/P2P bandwidth-regression runbook: ACS-redirect diagnosis and fix, shared root cause with the GDR-disabled branch here.
- the fabric-manager runbook: when the degraded path is NVLink/NVSwitch rather than inter-node IB/RoCE.
- the GPU-fault runbook: route here if a node shows a fatal XID rather than a clean fallback.
- operational runbooks: operational runbooks index.
References¶
- NCCL environment variables (
NCCL_IB_HCA,NCCL_IB_DISABLE,NCCL_NET_GDR_LEVEL,NCCL_DEBUG): https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html - NCCL networking troubleshooting (transports, GDR, fallback): https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting/networking_troubleshooting.html
- nccl-tests performance metrics (algbw/busbw, AllReduce correction factor): https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md
- nvidia-smi manual (
dmonmetric groups,smand PCIe-throughput column semantics): https://docs.nvidia.com/deploy/nvidia-smi/index.html - NVIDIA GPU Operator, GPUDirect RDMA (DMA-BUF vs legacy
nvidia_peermem): https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-operator-rdma.html - Mellanox/NVIDIA
k8s-rdma-shared-dev-plugin(RDMA device-plugin resources): https://github.com/Mellanox/k8s-rdma-shared-dev-plugin - PCI-SIG ACS Engineering Change Notice (P2P Request Redirect): https://pdos.csail.mit.edu/~sbw/links/ECN_access_control_061011.pdf
- Chris Fregly, AI Systems Performance Engineering (O'Reilly), Ch. 4, "Tuning Distributed Networking Communication": the silent socket-fallback behaviour without container access to
/dev/infiniband, the GID-mismatch trap, and the CPU-spike/GPU-idle fallback signature.
Related: NCCL Hang / Collective Stall · RDMA and RoCE Performance Tuning · NCCL Collectives & Algorithms · Fabric Bring-Up, Validation and Benchmarking · Diagnostics Tools · nvidia-smi Reference · PCIe / P2P Bandwidth Regression · Manifest: NicClusterPolicy · Operational Runbooks · Glossary
-
Fregly, Ch. 4: without container access to
/dev/infiniband, NCCL silently falls back to TCP, throughput drops from tens of GB/s to a few Gb/s with no error message; a red flag during a collective is GPU utilisation dropping while CPU utilisation spikes, since the CPU is copying data for communications. The 400 MB / 800 Gb/s worked example: a CPU-bound Gloo-style path runs approximately 200 ms (approximately 2 GB/s, CPU near 100%) versus approximately 4 ms (approximately 100 GB/s, line rate) with GPUDirect RDMA engaged. Illustrative figures from the book, not hardware-tested here. ↩↩↩ -
nccl-tests PERFORMANCE.md:
algbw = size/time; for AllReduce,busbw = algbw * 2*(n-1)/n; busbw reflects hardware utilisation independent of rank count, for comparison against hardware peak. https://github.com/NVIDIA/nccl-tests/blob/master/doc/PERFORMANCE.md ↩ -
nvidia-smi manual:
dmonmetric groups selected with-s;ureports utilisation includingsm(percentage of time at least one SM was busy);treports PCIe Rx/Tx throughput in MB/s.dmonhas no host-CPU column; pair with a host tool (mpstat,top) to see host-side load. https://docs.nvidia.com/deploy/nvidia-smi/index.html ↩ -
Fregly, Ch. 4: mismatched container/host GID assignments block GPUDirect registration and force CPU-driven RDMA copies instead of true GPU RDMA. ↩
-
NVIDIA GPU Operator, GPUDirect RDMA: DMA-BUF is the current recommended path (Open Kernel Module driver, CUDA >= 11.7, Turing-or-newer data-center/RTX/Quadro-RTX GPU, Linux kernel >= 5.12) and the helm-install default; the legacy
nvidia_peermemkernel module needs--set driver.rdma.enabled=trueexplicitly. https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-operator-rdma.html ↩