====== Rank and busbw for network troubleshooting ====== ===== What a rank is, in network terms ===== A **rank** is one process of the training job. Normally there is one per GPU, so for you **a rank = one GPU and its NIC**: one physical endpoint on the fabric. ^ AI-team term ^ Your translation (H200, rail-optimised) ^ | Global rank | One GPU in the job, numbered 0 … N−1 across all nodes | | Local rank | GPU index inside the node (0-7) | | World size | Total GPUs in the job (nodes × 8) | | Communicator | The set of GPUs taking part in a given collective, usually all of them | | Rank → NIC | Local rank //i// → GPU //i// → NIC //i// → **rail //i//** → a port on rail //i//'s leaf | So rank 13 on 8-GPU nodes is typically node 1, GPU 5, NIC 5, rail-5 leaf, port //x//. The "typically" matters, because two things can break the clean mapping: * **The launcher decides the rank order.** Rank → hostname comes from the job's hostfile or Slurm allocation, not from any fixed rule. Get it from the app team. * **NCCL's PXN feature** can move data over NVLink to another GPU's NIC so traffic stays on the destination's rail. A rank's traffic doesn't always leave via "its" NIC. How to pin it down with facts rather than assumptions: - Get rank → hostname from the scheduler (Slurm job info or the launcher hostfile). - Get local rank → NIC from the NCCL debug output (''NCCL_DEBUG=INFO''), which logs which IB device each rank uses. - Get NIC → GUID/LID from ''ibstat'' on the host. - Get GUID → leaf switch and port from UFM, or ''iblinkinfo'' / ''ibnetdiscover''. That chain turns "rank 13 is slow" into "node X, mlx5_5, leaf Y port Z", which is the language you troubleshoot in. ===== busbw, rewritten with that mapping ===== * A multi-node all-reduce uses **every GPU, every NIC (all 8 rails) and every switch path between them** at the same time, plus NVLink inside each node. * NCCL splits the data into parallel channels across the NICs. The collective completes only when the **slowest** channel finishes. * So low busbw (vs. baseline) means **at least one element in this physical set is degraded**: * a GPU or NVLink/NVSwitch inside any node, * any of the N × 8 NICs (or its PCIe link), * any NIC-to-leaf cable or optic, * any leaf, uplink or spine on the paths between those leaves. * One bad element anywhere drags the **whole job** down. busbw tells you the set is unhealthy, not which element. * busbw is normalised for job size, so a 2-node test and a 64-node test are directly comparable. That's what makes bisection work. ===== Locating the element: shrink the set until the fault is isolated ===== ^ Step ^ Test ^ What you've isolated ^ If low ^ | 1 | All-reduce inside each node (8 GPUs, no IB) | NVLink/GPU, per node | That node's internals. **Not the network** | | 2 | All-reduce across all job nodes | Whole set | Continue. If normal, the **network is likely not the cause**: check compute stragglers, storage, data loading | | 3 | 2-node tests (pairs on the same leaves) | Node pair | Outlier node found | | 4 | Per-NIC on the outlier node (NCCL restricted to one NIC, or ''ib_write_bw'' per NIC pair) | One rail on one node | NIC, PCIe, optic, cable or leaf port of that rail | | 5 | Same-leaf pair vs. cross-leaf vs. cross-SU | Switch tier | Uplinks, spine, adaptive routing, congestion | Then confirm in telemetry for the specific leaf/port you've identified: error counters, BER, speed/width downgrade, congestion counters. ===== How to run it ===== ==== Where from ==== * Run from the cluster's **login/head node**, launching onto the suspect nodes through the scheduler (Slurm) or MPI. * The nodes must be **drained or freed** from the slow job first. The test needs all GPUs and NICs. * Use the **same software stack as the job** (driver, CUDA, NCCL version, container image if they use one). A different NCCL version can give a different busbw and invalidate the comparison with the job. * Build once on shared storage so every node sees the same binary. ==== Build nccl-tests (once) ==== git clone https://github.com/NVIDIA/nccl-tests.git cd nccl-tests make MPI=1 MPI_HOME=/path/to/mpi CUDA_HOME=/usr/local/cuda NCCL_HOME=/path/to/nccl Binaries land in ''build/'', e.g. ''build/all_reduce_perf''. ==== Step 1: single node (NVLink only, no network) ==== One process driving all 8 GPUs: ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 8 * ''-b 8 -e 8G'': message sizes from 8 bytes to 8 GB * ''-f 2'': double the size each step * ''-g 8'': 8 GPUs in this process ==== Steps 2-3: multi-node (2 nodes = 16 ranks, 1 GPU per rank) ==== With Slurm: srun -N 2 --ntasks-per-node=8 --gpus-per-node=8 \ -w node01,node02 \ ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1 With mpirun: mpirun -np 16 -H node01:8,node02:8 \ -x NCCL_DEBUG=INFO \ ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1 ''NCCL_DEBUG=INFO'' also prints which IB device each rank uses: this gives you the rank → NIC mapping. ==== Step 4: one rail only ==== Restrict NCCL to a single NIC (here rail 5): mpirun -np 2 -H node01:1,node02:1 \ -x NCCL_IB_HCA==mlx5_5 \ -x CUDA_VISIBLE_DEVICES=5 \ ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1 Or test the raw RDMA path without NCCL, NIC to NIC: # on node02 (server) ib_write_bw -d mlx5_5 --report_gbits # on node01 (client) ib_write_bw -d mlx5_5 --report_gbits node02 Repeat for each rail (mlx5_0 … mlx5_7). ==== Check the link you've isolated ==== ibstat mlx5_5 # state, rate (expect 400), physical state iblinkinfo | grep -i # which leaf and port it lands on ==== Reading the output ==== nccl-tests prints one line per message size, with ''algbw'' and ''busbw'' columns for out-of-place and in-place runs, then an ''Avg bus bandwidth'' summary line. Compare the **busbw at the largest sizes** (and the whole curve) with your baseline for the same node count and topology. **Verify on your system:** Slurm may need ''--mpi=pmix'' (or similar) depending on how MPI was built. The ''NCCL_IB_HCA'' syntax (a leading ''='' for an exact device-name match) and the device names (''mlx5_N'') depend on your NCCL version and host. Check ''ibv_devices'' for the real names. ===== Reading the result ===== * **Large messages, low plateau:** lost bandwidth. Look for a degraded or downgraded link, a NIC at the wrong PCIe width, or a link down shrinking the path set. * **Small messages slow:** latency. Look for extra hops, adaptive-routing problems, or SHARP not in use. * **Fine at 2 nodes, worse at scale:** spine, uplink or congestion problem. * **Normal busbw, slow job:** the fabric is likely fine. Ask the app team for per-rank step times. A slow rank points at a specific GPU/node, which you can map back with the chain above. **Limit:** nccl-tests need the nodes, so the job must be drained or paused.