The Diagnostic Pivot: When IOMMU Broke GPU P2P DMA

Message: [bash] ssh root@10.1.230.174 'kill -9 $(pgrep -f sglang) 2>/dev/null; fuser -k /dev/nvidia* 2>/dev/null; sleep 2; ~/ml-env/bin/python3 /root/gpu_diag.py 2>&1'

At first glance, this message looks like a routine command: kill any lingering SGLang processes, release GPU device handles, wait a moment, then run a diagnostic script. But in the arc of this coding session, this message represents a critical inflection point — the moment when the assistant pivoted from trying to fix a broken deployment through configuration changes to running bare-metal diagnostics to understand why the deployment was broken at the hardware level. It is the bridge between a failed hypothesis and a confirmed root cause.

The Crisis That Preceded This Message

To understand why this message was written, one must understand the cascade of failures that led to it. The assistant had been deploying the Qwen3.5-122B-A10B model (a 234 GB BF16 model) across 4 NVIDIA RTX PRO 6000 Blackwell GPUs in an LXC container on a Proxmox host. The server had been reconfigured in a previous segment ([msg 6196]): the 8 GPUs were split, with 4 bound to the nvidia driver for the container and 4 moved to vfio-pci for a SEV-SNP confidential VM. This reconfiguration enabled amd_iommu=on in full translation mode — a requirement for SEV-SNP — which fundamentally changed how PCIe devices could communicate.

The symptom was unmistakable: SGLang would hang during init_torch_distributed, with all 4 TP workers blocked on futex and socket reads ([msg 6172]). The assistant spent multiple rounds chasing this as a software issue — checking NCCL environment variables, testing different transport protocols, pulling the latest SGLang commits, reinstalling from source. Each attempt failed identically. The server would start loading, the GPUs would allocate ~1 GB of memory each, and then everything would freeze.

Then the user provided the missing piece: IO_PAGE_FAULT logs from the Proxmox host's kernel ([msg 6191]). Lines like nvidia 0000:01:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x002c address=0x24000000000 flags=0x0030] revealed that the NVIDIA GPUs were attempting Direct Memory Access to addresses that the IOMMU (AMD-Vi) refused to translate. The flags=0x0030 pattern indicated a write to a non-present page — the IOMMU had no mapping for the target address.

Why This Message Was Written

The assistant's reasoning, visible in the preceding messages ([msg 6209], [msg 6211]), shows a clear diagnostic chain:

  1. Observation: IO_PAGE_FAULTs involve addresses like 0x24000000000 and 0x34000010000, which match the BAR (Base Address Register) ranges of other GPUs.
  2. Hypothesis: The GPUs are attempting P2P (peer-to-peer) DMA directly to each other's memory, which is the standard path for NCCL all-reduce operations. Under full IOMMU translation, these direct physical addresses are invalid because the IOMMU requires IOVA (I/O Virtual Addresses), not raw physical addresses.
  3. Implication: If P2P DMA is broken, NCCL cannot initialize because it relies on cudaDeviceEnablePeerAccess to establish direct GPU-to-GPU communication channels.
  4. Action: Before attempting any more complex fixes (like patching NCCL or SGLang to avoid P2P), the assistant needed to confirm that the GPUs themselves were functional and that the only broken path was P2P DMA. This message executes that action. It runs gpu_diag.py — a diagnostic script the assistant had just written and transferred via SCP ([msg 6212]) — which was designed to test basic single-GPU CUDA operations and explicit P2P transfers between GPU pairs.

The Thinking Process: What the Assistant Expected

The assistant's reasoning reveals several assumptions. First, it assumed that single-GPU operations would work fine — the GPUs had been verified earlier in the session (segment 39) and were allocating memory normally. The real question was whether cudaDeviceCanAccessPeer and cudaDeviceEnablePeerAccess would succeed or fail. The script was structured to test both paths: basic tensor operations on each GPU individually, followed by cross-GPU P2P transfers.

Second, the assistant assumed that the diagnostic script would produce visible output — either confirming P2P failure with specific error messages, or unexpectedly succeeding (which would point the investigation back toward software). The 2>&1 redirection was deliberate: it captured both stdout and stderr to ensure no diagnostic information was lost.

Third, the assistant assumed that killing SGLang processes and releasing GPU handles with fuser -k /dev/nvidia* was necessary to avoid resource conflicts. The sleep 2 provided a grace period for the NVIDIA driver to release internal state.

Input Knowledge Required

Understanding this message requires knowledge spanning several domains:

Output Knowledge Created

The output of this message was, unexpectedly, nothing at all. The next message ([msg 6214]) reveals: "No output at all." The diagnostic script produced zero output — not even an error message. This silence was itself a data point. It meant the script either:

The Broader Significance

This message exemplifies a pattern that recurs throughout the session: when high-level configuration fixes fail, the assistant systematically strips away layers of abstraction to test the hardware directly. The diagnostic script was the assistant's attempt to isolate the IOMMU hypothesis from confounding variables like NCCL versions, SGLang patches, or PyTorch compatibility. By running a minimal CUDA test outside the SGLang framework, the assistant could determine whether the problem was in the application layer or the hardware/driver layer.

The empty output forced a further simplification — the inline Python one-liner — which finally confirmed the baseline. From there, the assistant would go on to discover that NCCL_P2P_DISABLE=1 (forcing NCCL to use shared memory transport instead of P2P DMA) resolved the hang entirely, and the server would eventually achieve 2,800 tok/s at high concurrency. But that solution depended entirely on first understanding that P2P DMA was the broken link — understanding that began with this seemingly unremarkable command.