Every team that operates GPU clusters for AI has seen this pattern. The cluster boots, GPUs are visible, and scheduling works at a basic level. Then the first distributed training run stalls in NCCL initialization, fails during rank rendezvous, or silently maps ranks to the wrong devices. The issue is often not in training code. It is in infrastructure consistency across scheduler, runtime, drivers, networking, and process topology.
The goal of ai-infra-validator is straightforward:
- Run a fast user space preflight before expensive training jobs.
- Validate distributed initialization for multi node, multi GPU workloads.
- Confirm GPU affinity and rank mapping are correct.
- Verify NCCL communication fabric can complete a collective ring under Slurm.
This post walks through the implementation in detail, explains why each part exists, and shows how to operationalize it in real HPC AI environments.
What the project validates
Zero-dependency user space smoke test for AI clusters. Validates multi-node PyTorch DDP initialization, GPU affinity, and NCCL fabric connectivity under Slurm orchestration.
Git Repo: ai-cluster-validator
In practical terms, this checks that:
- Slurm launches the expected number of ranks per node.
- Distributed process group creation with NCCL succeeds.
- Each rank binds to the expected local GPU.
- Cross-rank all-reduce completes and converges.
- Node level telemetry confirms software and fabric state.
This is not a performance benchmark. It is a correctness and readiness gate.
Tested platform profile
| Component | Value |
|---|---|
| CycleCloud | 8.8.3-3667 |
| Slurm | 25.05.5 |
| Slurm partition | hpc |
| Scheduler VM SKU | Standard_D8s_v6 |
| Compute VM SKU | Standard_ND96asr_v4 |
| OS images | microsoft-dsvm:ubuntu-hpc:2204:latest and microsoft-dsvm:ubuntu-hpc:2404:latest |
| PyTorch | 2.12.0+cu130 |
| CUDA runtime | 13.0 |
| NCCL target | 2.29.7 |
This profile represents a common enterprise scenario where scheduler and compute nodes have different roles, and the training fleet depends on correct multi node orchestration.
Step 1: Minimal user space bootstrap
The bootstrap script creates a shared Python environment at /shared/apps/pytorch_env and installs the required packages:
- torch
- torchvision
- torchaudio
- psutil
This choice is intentional:
- No dependency on containers for first-pass validation.
- Single environment path visible to all compute nodes.
- Rapid setup and repeatability for cluster operators.
Command sequence:
cd ai-cluster-validator
sudo bash bootstrap_env.sh
Step 2: Slurm job defines deterministic distributed topology
The Slurm script expresses a clear topology contract:
- nodes=2
- ntasks-per-node=8
- gpus-per-node=8
- cpus-per-task=12
From this, world size is derived as:
WORLD_SIZE = SLURM_NTASKS = 2 x 8 = 16
The script also configures network and NCCL behavior:
- NCCL_DEBUG=WARN
- NCCL_IB_DISABLE=0
- NCCL_P2P_DISABLE=0
- NCCL_IGNORE_CPU_AFFINITY=1
- GLOO_SOCKET_IFNAME=eth0
- NCCL_SOCKET_IFNAME=eth0
Important implementation detail:
- MASTER_ADDR is set to the first host in SLURM_JOB_NODELIST.
- MASTER_PORT is selected dynamically from the ephemeral range 49152-65535 and falls back to 29500 if needed.
Why this matters:
- Reduces port collision risk when jobs run frequently.
- Avoids hardcoded rendezvous values that may fail in shared clusters.
Launch path:
source /shared/apps/pytorch_env/bin/activate;
export RANK=$SLURM_PROCID;
export LOCAL_RANK=$SLURM_LOCALID;
python3 ddp_mesh_ping.py
“
The LOCAL_RANK handoff is critical for stable GPU affinity inside each node.
Step 3: DDP initialization and rank to GPU affinity
Inside ddp_mesh_ping.py, each process executes:
- Parse WORLD_SIZE, RANK, LOCAL_RANK, MASTER_ADDR, MASTER_PORT.
- Initialize torch.distributed with backend nccl and TCP init method.
- Set CUDA device using LOCAL_RANK.
Core initialization path:
backend=”nccl”,
init_method=f”tcp://{master_addr}:{master_port}”,
world_size=world_size,
rank=rank
)
torch.cuda.set_device(local_rank)
This validates the minimum distributed contract required by real model training jobs.
Step 4: Rich node and fabric telemetry in user space
Each rank collects detailed metadata before the collective test:
- Node identity from Slurm and hostname.
- GPU model and VRAM from CUDA properties.
- System memory via psutil.
- CPU model from /proc/cpuinfo.
- OS and kernel versions.
- NVIDIA driver version from /proc/driver/nvidia/version.
- PyTorch, CUDA, and NCCL runtime versions.
- InfiniBand device state and link rate from /sys/class/infiniband.
- Basic GPU peer access capability via torch.cuda.can_device_access_peer.
All rank payloads are gathered on rank 0 using dist.gather_object and printed as:
- Cluster hardware topology report.
- Node environment deep dive.
- Network interconnect and fabric status.
This design gives platform teams one artifact that is both operational and diagnostic.
Step 5: Functional collective validation
After telemetry, each rank executes a lightweight DDP compute path:
- Build nn.Linear(10,10) on local GPU.
- Wrap with DistributedDataParallel.
- Perform forward, loss, backward.
- Run all_reduce on loss tensor.
- Compute global average loss.
Pass condition is explicit in log output:
SUCCESS: DDP Multi-Node AllReduce Ring Complete!
This confirms that process group initialization and collective communication both completed successfully.
What a successful run looks like
Submission:
squeue
Representative outcomes in the log:
- Total Execution Ranks: 16
- Two nodes with local ranks 0 through 7 on each node
- GPU inventory aligned with expected A100 topology
- Active InfiniBand HCAs discovered per host
- NCCL socket interface set to eth0
- Final success marker and computed convergence loss
When these markers are present and coherent with expected hardware shape, the cluster is typically ready for distributed training bring-up.
How to check the output file
The Slurm script writes two artifacts per job:
- ai_infra_smoke_test_
.log - ai_infra_smoke_test_
.err
Use this exact workflow after submission:
sbatch ddp_smoke_test.slurm
# 2. Check job state
squeue -j
# 3. Read standard output log
cat ai_infra_smoke_test_
# 4. Read standard error log
cat ai_infra_smoke_test_
For stronger validation in automation, also check:
Total Execution Ranksequals expected world size.- Both nodes appear in the topology table with local ranks 0 through 7.
- NCCL/CUDA/PyTorch versions are present in the node environment section.
Complete reference output
Use the following full log as a known-good reference from a successful 2-node ND96asr_v4 run.
Dynamically Assigned Port: 53593
Total Execution Ranks: 16
===============================================================================================
HPC CLUSTER INTERACTION MONITOR
===============================================================================================
–> Initializing DDP on Master Node : ddpcluster-hpc-1
–> Dynamic Coordination Port : 53593
–> Target World Cluster Size : 16 GPUs
———————————————————————————————–
===============================================================================================
CLUSTER HARDWARE TOPOLOGY REPORT
===============================================================================================
| Rank | Node Name | Local ID | GPU Model | VRAM | Sys Mem | CPU Cores |
———————————————————————————————–
| 0 | ddpcluster-hpc-1 | 0 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 1 | ddpcluster-hpc-1 | 1 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 2 | ddpcluster-hpc-1 | 2 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 3 | ddpcluster-hpc-1 | 3 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 4 | ddpcluster-hpc-1 | 4 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 5 | ddpcluster-hpc-1 | 5 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 6 | ddpcluster-hpc-1 | 6 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 7 | ddpcluster-hpc-1 | 7 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 8 | ddpcluster-hpc-2 | 0 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 9 | ddpcluster-hpc-2 | 1 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 10 | ddpcluster-hpc-2 | 2 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 11 | ddpcluster-hpc-2 | 3 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 12 | ddpcluster-hpc-2 | 4 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 13 | ddpcluster-hpc-2 | 5 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 14 | ddpcluster-hpc-2 | 6 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
| 15 | ddpcluster-hpc-2 | 7 | NVIDIA A100-SXM4-4 | 39.5 GB | 885.8 GB | 96 Cores |
===============================================================================================
NODE ENVIRONMENT DEEP DIVE
———————————————————————————————–
[ddpcluster-hpc-1] Details:
–> CPU Microarchitecture : AMD EPYC 7V12 64-Core Processor
–> Operating System : Ubuntu 22.04.5 LTS
–> Kernel Base Version : 5.15.0-1110-azure
–> Nvidia Driver Loaded : 580.126.20
–> PyTorch Environment : v2.12.0+cu130
–> CUDA Runtime Version : v13.0
–> NCCL Fabric Target : v2.29.7
–> Discovered InfiniBand HCAs:
– mlx5_an0:1 (4: ACTIVE – 40 Gb/sec (4X QDR))
– mlx5_ib0:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib1:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib2:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib3:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib4:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib5:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib6:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib7:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
———————————————————————————————–
[ddpcluster-hpc-2] Details:
–> CPU Microarchitecture : AMD EPYC 7V12 64-Core Processor
–> Operating System : Ubuntu 22.04.5 LTS
–> Kernel Base Version : 5.15.0-1110-azure
–> Nvidia Driver Loaded : 580.126.20
–> PyTorch Environment : v2.12.0+cu130
–> CUDA Runtime Version : v13.0
–> NCCL Fabric Target : v2.29.7
–> Discovered InfiniBand HCAs:
– mlx5_an0:1 (4: ACTIVE – 40 Gb/sec (4X QDR))
– mlx5_ib0:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib1:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib2:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib3:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib4:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib5:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib6:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
– mlx5_ib7:1 (4: ACTIVE – 200 Gb/sec (4X HDR))
———————————————————————————————–
NETWORK INTERCONNECT & FABRIC STATUS
———————————————————————————————–
–> Target Communication Interface (NCCL_SOCKET_IFNAME) : eth0
–> Active Telemetry Tracking Level (NCCL_DEBUG) : WARN
–> Inter-GPU Topo Link Verification : Active (P2P/NVLink Capable)
———————————————————————————————–
SUCCESS: DDP Multi-Node AllReduce Ring Complete!
–> Computed System Verification Convergence Loss : 1.398719
===============================================================================================
Why this is effective for platform operations
For AI infrastructure teams, this pattern is highly effective because it is:
- Fast: can be run after every change window.
- Deterministic: same topology contracts every run.
- Actionable: output includes enough context for first-level triage.
- Low friction: user space only, no heavy control plane dependencies.
This supports common operating workflows:
- Day-0 cluster acceptance.
- Day-1 patch validation after driver, kernel, or image changes.
- Regression gate in golden image pipelines.
- Preflight before large multi node model training jobs.
Practical guidance for extending to larger clusters
- Adjust Slurm directives for nodes and tasks per node.
- Keep one rank per GPU unless validating alternate placement policy.
- Set NCCL_SOCKET_IFNAME and GLOO_SOCKET_IFNAME according to your network policy.
- Preserve the dynamic MASTER_PORT logic to avoid static collisions.
- Keep the success marker string stable so automation can parse it.
Closing perspective
Most distributed training failures are expensive because they are discovered late. A user space preflight that validates scheduler topology, rank rendezvous, GPU affinity, and NCCL collectives provides a high value guardrail before production starts.
ai-infra-validator is a practical implementation of that guardrail. It is compact, transparent, and aligned with how real Slurm based AI clusters operate. For teams running multi node multi gpu training at scale, this kind of preflight should be a standard operational gate.
