NVIDIA GPU Architectures Series — Presentation 14

PCIe & GPUDirect — The Bus Every GPU Sits On

Even when NVLink does the heavy lifting, every GPU still hangs off PCIe — and what the system board does there decides whether your tensor parallelism scales, your storage paths bypass the CPU, and your driver finds peer GPUs at all. A grounded look at lanes, ReBAR, IOMMU, NUMA, P2P, and GPUDirect Storage.

PCIe 4PCIe 5PCIe 6 ReBARIOMMUACS NUMAP2P GPUDirect StorageBAR1
PCIe 3 → 4 → 5 → 6 → ReBAR → IOMMU → P2P → GDS
00

Topics We'll Cover

Every GPU sits on PCIe, even the ones that mostly talk to siblings over NVLink. The board layer underneath the driver decides whether peer-to-peer works, how fast cold loads run, and whether your eight-GPU box is actually one fabric or two halves stitched through a CPU socket.

01

PCIe in One Page

PCI Express is bidirectional, packet-switched, point-to-point serial. Each lane is one differential pair per direction; a link is a bundle of lanes (x1, x4, x8, x16). Every generation roughly doubles the per-lane raw rate; the encoding evolves alongside (8b/10b on Gen1/2, 128b/130b from Gen3, PAM4 on Gen6).

GenPer-lane ratePer-lane bandwidthx16 link (per direction)Encoding
PCIe 3.08 GT/s~1 GB/s~16 GB/s128b/130b NRZ
PCIe 4.016 GT/s~2 GB/s~32 GB/s128b/130b NRZ
PCIe 5.032 GT/s~4 GB/s~64 GB/s128b/130b NRZ
PCIe 6.064 GT/s~8 GB/s~128 GB/sPAM4 + FLIT + FEC

Lane configurations you'll actually meet

Reality check

PCIe is bidirectional and point-to-point but the headline numbers always quote per direction. A "32 GB/s PCIe 4 x16 link" pushes 32 GB/s up and 32 GB/s down at the same time; aggregate is 64 GB/s. Useful for P2P where two GPUs send and receive in parallel.

02

GPU Generation → PCIe Generation

Each GPU architecture pins itself to one PCIe generation at the host edge. The interesting twist: NVLink bandwidth on the same card has been pulling away from PCIe ever since Volta — the bus is the cheap path, NVLink is the fast one.

ArchitectureExamplesPCIe genx16 BW (per direction)NVLink (where present)
PascalP100PCIe 3.0~16 GB/sNVLink 1, 4 links, 160 GB/s aggregate
VoltaV100PCIe 3.0~16 GB/sNVLink 2, 6 links, 300 GB/s aggregate
TuringT4, RTX 20-seriesPCIe 3.0~16 GB/sNVLink bridge on RTX 2080 / 2080 Super / 2080 Ti, Titan RTX, Quadro RTX
AmpereA100, RTX 30-seriesPCIe 4.0~32 GB/sNVLink 3, 600 GB/s on A100 SXM
Ada LovelaceL40S, RTX 40-seriesPCIe 4.0~32 GB/sNone on consumer; none on L40S
HopperH100, H200PCIe 5.0~64 GB/sNVLink 4, 18 links × 50 GB/s = 900 GB/s on SXM5
BlackwellB200, RTX 50-seriesPCIe 5.0~64 GB/sNVLink 5, 1.8 TB/s on B200; NVL72 domains
Rubin (expected)Vera Rubin platformPCIe 6.0 expected~128 GB/sNVLink 6 expected
The numbers that matter

An H100 SXM5 talks to its host over PCIe 5 x16 at ~64 GB/s per direction (~128 GB/s bidirectional). The same card talks to its seven NVSwitch-connected siblings at 900 GB/s aggregate bidirectional (18 NVLink-4 links × 25 GB/s/dir, or equivalently 50 GB/s bidirectional per link). That is roughly 7× the host bus. Anything you care about — tensor-parallel all-reduce, KV migration, expert routing — should ride NVLink, not PCIe. PCIe is for boot, weight loading, NVMe traffic, NIC traffic, and management.

What a PCIe-only GPU loses

A "PCIe edition" H100 (no NVLink bridge across cards) ganged with another via PCIe 5 x16 sees ~64 GB/s peer-to-peer. The same pair of H100 SXM5 cards on a HGX baseboard sees 900 GB/s. Tensor parallelism on the PCIe pair is bandwidth-starved on every all-reduce; that's why DGX/HGX exist.

03

BAR, BAR1 & Resizable BAR

A PCIe device exposes its memory to the host through Base Address Registers (BARs). Each BAR is a window into the device's address space that the host CPU can map into its own virtual memory. For an NVIDIA GPU, BAR1 is the window onto VRAM — the aperture through which the CPU and other devices see GPU memory.

Legacy BAR1: 256 MB

Historically, BAR1 was a fixed 256 MB window. To cudaMemcpy a 24 GB tensor, the driver chunks the transfer through that window in pieces, doing 96 round trips. Each chunk costs setup latency. The full bandwidth of PCIe is rarely reached on cold loads.

Resizable BAR (ReBAR)

PCIe specification feature, marketed as "Above 4G Decoding" or "Smart Access Memory". The BAR is renegotiated at boot to cover the entire VRAM in one window: 24 GB on an RTX 4090, 80 GB on an H100, 192 GB on a B200. The CPU sees all of VRAM in one mapping. No chunking.

What ReBAR actually delivers

Always enable in BIOS

Look for "Above 4G Decoding" + "Re-Size BAR Support". On consumer Intel boards (12th gen+) and AMD AM4/AM5/SP3 platforms it's a toggle. On older boards it may be missing entirely — ReBAR depends on system memory map cooperation that pre-2020 boards simply can't provide. Verify after boot:

Verify ReBAR is active
lspci -vvv -s 01:00.0 | grep -A1 'Region 1:'
# Expect: Region 1: Memory at ... (64-bit, prefetchable) [size=24G]
# Bad   : Region 1: Memory at ... (64-bit, prefetchable) [size=256M]

# Or via NVIDIA driver:
nvidia-smi -q | grep -i bar1
# BAR1 Memory Usage
#     Total                             : 24576 MiB   ← full VRAM = ReBAR on
#     Total                             : 256 MiB     ← legacy = ReBAR off
04

IOMMU & ACS

The IOMMU (Intel VT-d, AMD-Vi) is the device-side equivalent of the CPU's MMU. It virtualises DMA addresses: a device's view of memory is translated by the IOMMU before reaching the memory controller. Two reasons it exists: VM passthrough, and protection from buggy or malicious DMA.

The two operating modes that matter

iommu=pt (passthrough)

The IOMMU is enabled for VM use cases but the host itself uses an identity map — DMAs go through real physical addresses, no translation overhead. Default on most distros. P2P-friendly. Fastest. Use this for bare-metal GPU serving.

iommu=on (full translation)

Every DMA is remapped. Required for VFIO / GPU passthrough into VMs (and for confidential computing). Slower — small but measurable. Can break P2P if peer windows aren't mapped into the same domain. Use only when you need passthrough.

ACS — Access Control Services

ACS is a PCIe feature implemented by switches and root ports. It tells the fabric whether peer-to-peer traffic between two downstream devices should be routed directly (peer-to-peer DMA) or upstream-redirected (forced through the host root complex). ACS exists because the IOMMU can only enforce isolation on traffic it actually sees — if two devices talk peer-to-peer behind a switch, the IOMMU is bypassed.

Diagnose IOMMU groups and ACS
# Which IOMMU mode is active?
dmesg | grep -E 'IOMMU|DMAR|AMD-Vi' | head -20

# Which devices share an IOMMU group?
for g in /sys/kernel/iommu_groups/*; do
    echo "Group ${g##*/}:"
    ls $g/devices
done

# Is ACS enabled on root ports / switches?
sudo lspci -vvv | grep -E 'IOMMU|ACSCtl'
# ACSCtl: SrcValid+ TransBlk- ReqRedir+ CmpltRedir+ ...   ← redirect on = blocks P2P
# ACSCtl: SrcValid- TransBlk- ReqRedir- CmpltRedir- ...   ← clean for P2P
Server vs consumer surprise

Consumer boards (cheap ACS) tend to make P2P trivially work but VM passthrough hard. Server boards behind PLX/Microchip switches often block P2P by default to satisfy ACS-strict virtualization, even though the silicon supports it. If P2P is mysteriously broken on a fancy server, check ACS before blaming the driver.

05

P2P — GPU↔GPU Without Host Memory

Peer-to-peer DMA lets one GPU read or write the memory of another GPU directly across PCIe (or NVLink, when present), without staging through host RAM. The path is: GPU A → PCIe root complex (or switch) → GPU B. CPU is uninvolved beyond setting up the mappings.

P2P path vs host-staged path GPU A PCIe root / switch GPU B Host RAM P2P: GPU A → root → GPU B (single hop) staged copy: GPU A → host → GPU B (2x bandwidth, 2x latency)

Requirements for P2P to actually work

Test and use P2P from CUDA
// Check capability
int can_p2p;
cudaDeviceCanAccessPeer(&can_p2p, 0, 1);
if (!can_p2p) { /* fall back to host-staged */ }

// Enable both directions
cudaSetDevice(0); cudaDeviceEnablePeerAccess(1, 0);
cudaSetDevice(1); cudaDeviceEnablePeerAccess(0, 0);

// Direct copy
cudaSetDevice(0);
cudaMemcpyPeerAsync(dst1, 1, src0, 0, n, stream);

// Or use the simpleP2P sample for a calibrated bandwidth measurement:
//   cuda-samples/Samples/0_Introduction/simpleP2P
Numbers

P2P bandwidth on PCIe 4 x16 tops out around 26-28 GB/s effective per direction (out of 32 GB/s raw, after PCIe overhead). On PCIe 5 x16, ~52-56 GB/s per direction. Latency is ~3-5 μs setup. NVLink-4 delivers 25 GB/s per direction per link (50 GB/s bidirectional per link), and an H100 SXM5 has 18 of them for 900 GB/s bidirectional aggregate — ~7× the headline P2P-on-PCIe-5 number.

06

NUMA & Multi-Socket Pinning

Two-CPU servers (and the few four-socket beasts that survive) are NUMA — non-uniform memory access. Each socket owns half the DRAM channels and half the PCIe lanes. Each GPU is wired to one socket. Cross-socket GPU traffic hops the inter-socket link — UPI on Intel, Infinity Fabric on AMD — which is slower and adds latency.

Two-socket server — one GPU local, one cross-socket CPU 0 (NUMA 0) GPU 0 GPU 1 CPU 1 (NUMA 1) GPU 2 GPU 3 UPI / Infinity Fabric — ~5x slower PIX intra-socket PIX intra-socket SYS = cross-socket (avoid for P2P)

What it costs you

The fix — pin everything

numactl, taskset, and CUDA_VISIBLE_DEVICES
# Inspect topology
numactl --hardware
nvidia-smi topo -m
nvidia-smi topo -p2p r          # P2P read capability matrix

# Pin a serving process to NUMA 0 with GPUs on socket 0
CUDA_VISIBLE_DEVICES=0,1 \
    numactl --cpunodebind=0 --membind=0 \
    vllm serve meta-llama/Llama-3.1-70B-Instruct --tensor-parallel-size 2

# For multi-process MPI / torchrun: rank-to-NUMA mapping by local rank
for rank in 0 1 2 3; do
    node=$((rank / 2))            # 2 GPUs per socket on this box
    numactl --cpunodebind=$node --membind=$node \
        python worker.py --rank $rank &
done
07

Reading the Topology

nvidia-smi topo -m is the single most useful diagnostic for multi-GPU performance debugging. It prints a matrix of how every GPU pair is connected, using a fixed vocabulary of link classes.

LabelMeaningPractical perf
NV#Direct NVLink, # = number of linksBest. e.g. NV18 = 18 NVLink-4 links via NVSwitch
PIXSingle PCIe bridge between the two GPUsGood. P2P at full PCIe x16 speed
PXBMultiple PCIe bridges traversedOK. Adds latency; bandwidth still bus-limited
PHBPCIe + a PCIe host bridge (typically the CPU root complex)Worse. Traffic turns round in the CPU; lower BW, higher latency
NODEWithin NUMA node but no direct PCIe path betweenVery poor. Often goes through CPU root complex
SYSCrosses CPU sockets (UPI / Infinity Fabric)Worst. P2P typically disabled. Avoid TP across this

Real example — 8×H100 SXM5 in DGX H100

nvidia-smi topo -m on DGX H100
      GPU0  GPU1  GPU2  GPU3  GPU4  GPU5  GPU6  GPU7  CPU Affinity  NUMA
GPU0   X    NV18  NV18  NV18  NV18  NV18  NV18  NV18  0-55,112-167   0
GPU1  NV18   X    NV18  NV18  NV18  NV18  NV18  NV18  0-55,112-167   0
GPU2  NV18  NV18   X    NV18  NV18  NV18  NV18  NV18  0-55,112-167   0
GPU3  NV18  NV18  NV18   X    NV18  NV18  NV18  NV18  0-55,112-167   0
GPU4  NV18  NV18  NV18  NV18   X    NV18  NV18  NV18  56-111,168-223 1
GPU5  NV18  NV18  NV18  NV18  NV18   X    NV18  NV18  56-111,168-223 1
GPU6  NV18  NV18  NV18  NV18  NV18  NV18   X    NV18  56-111,168-223 1
GPU7  NV18  NV18  NV18  NV18  NV18  NV18  NV18   X    56-111,168-223 1

Legend:  X = self  NV# = N NVLinks  PIX = single PCIe bridge  ...

Every pair shows NV18 — the NVSwitch fabric makes the 8 GPUs look like a single uniform NVLink domain. CPU affinity columns split 4/4 across two sockets, but the cross-socket SYS hop is hidden because all GPU-to-GPU traffic goes over NVSwitch, not over PCIe + UPI.

Real example — 2×RTX 4090 on a desktop board

Typical consumer ATX with two 4090s
      GPU0  GPU1  CPU Affinity  NUMA
GPU0   X    PIX   0-15           0
GPU1  PIX    X    0-15           0

# PIX = both GPUs hang off the same PCIe root port. P2P works.
# If instead you saw PHB or NODE, the second slot is on PCH-attached lanes
# and P2P will be slow or unreliable.
Diagnostic ladder

Run, in order: nvidia-smi topo -m (link classes), nvidia-smi topo -p2p r (read-side P2P), nvidia-smi nvlink -s (NVLink up/down per card), then ./bandwidthTest --device=0 --dtod (measured number). The matrix tells you what should work; the bandwidth test tells you what does work.

08

GPUDirect P2P, RDMA, Storage

"GPUDirect" is NVIDIA's umbrella for any path that lets a non-CPU device DMA into GPU memory or vice versa, bypassing host buffers. Three flavours actually matter for LLM and HPC work.

GPUDirect P2P

GPU↔GPU within a node, over PCIe or NVLink. The case from slide 5. Used by NCCL all-reduces, vLLM TP shards, and explicit cudaMemcpyPeer. Same-host, two GPUs, no host RAM hop.

Triggered by: cudaDeviceEnablePeerAccess, NCCL, IPC handles.

GPUDirect RDMA

GPU↔GPU across nodes via InfiniBand or RoCE. The NIC DMAs straight into GPU VRAM — no copy through host RAM. Required for any cross-node TP, and for the bandwidth claims in HGX/DGX SuperPOD literature to be true.

Stack: Mellanox/CX NIC + nvidia_peermem.ko kernel module (formerly nv_peer_mem) + UCX or NCCL.

GPUDirect Storage (GDS)

Storage↔GPU directly. NVMe SSD or distributed FS reads land in GPU VRAM, bypassing the host page cache and CPU bounce buffer. ~10× faster on checkpoint loading; large-batch dataset streaming.

API: cuFile. Kernel: nvidia-fs.ko. FS support: Lustre, GPFS/Spectrum Scale, WekaIO, BeeGFS, plus local NVMe.

The data path, side by side

Without vs with GPUDirect Storage on a 70 GB checkpoint
// Without GDS (standard POSIX read + cudaMemcpy):
NVMe SSD  →  PCIe  →  host page cache  →  user buffer  →  cudaMemcpyHtoD  →  GPU VRAM
          ^                                                       ^
          |  one PCIe traversal upstream                          |  another PCIe traversal back down
          |  CPU touches every byte                                  CPU touches every byte again

// With GDS (cuFile API):
NVMe SSD  →  PCIe  →  GPU VRAM
          ^
          |  single PCIe traversal, NVMe DMAs straight into VRAM
          |  CPU only manages the queue
          |  ~10x faster on a 70 GB checkpoint, >90% of NVMe headline BW
When GDS pays off

Checkpoint loading on big-model training, multi-node serving with shared distributed FS, and large dataset streaming. For day-to-day inference (weights stay resident in VRAM after first load), GDS is irrelevant. The clearest win is in TRT-LLM / vLLM cold-start time on a 70B+ FP8 checkpoint when host page cache isn't warm.

09

Persistent Mode, Power, Cooling

The bus discussion has knock-on effects on chassis, power, and driver state. Three operational details worth covering because they intersect directly with PCIe trade-offs.

Persistent mode

sudo nvidia-smi -pm 1. Without persistence, the kernel driver unloads the GPU each time the last process holding it exits, and re-initialises on the next open — ~30 s of overhead per cold start. For containerised serving where the orchestrator restarts pods, persistence is mandatory. Datacenter cards have it on by default; consumer cards don't.

Power limits

sudo nvidia-smi -pl 350 (watts). Cap a 4090 at 350 W and you lose ~5% throughput but ~15% power. Useful in dense racks where total wall-power is the constraint. Inspect envelopes with nvidia-smi -q -d POWER — cards have min/max enforced limits and a default.

Datacenter passive cooling

H100/H200/A100/L40S are passive — no fan on the card. They require 35+ CFM front-to-back airflow from chassis fans. Drop one into a quiet workstation case and it will throttle within minutes. The CFM number is on the card datasheet; do not improvise.

Consumer blower vs flow-through

Old-style consumer "blower" cards (3090 turbo edition, A6000) self-cool front-to-back — rack-friendly. Modern flow-through Founders Edition (RTX 4090 FE, 5090 FE) recirculate hot air through the heatsink — bad in 4U racks where the next card breathes the exhaust. Pick blower-style for any rack-mount build.

Why this is in a PCIe deck

Because chassis design and PCIe slot topology share the same constraint: dense multi-GPU boxes pack cards close together, which kills airflow, and put them on cheap PCH-attached lanes, which kills P2P. Server-class chassis (HGX, custom 4U with 8×PCIe) solve both at once — right cooling and right lane routing — and that's why they cost what they cost.

10

Multi-GPU on Consumer Boards — Where it Goes Wrong

"I bolted a second 4090 in and now everything's slow." Here is the standard menu of failure modes, in roughly the order you should check them.

#SymptomCauseFix
a Second GPU runs at PCIe x4 / x8 instead of x16 Board has 1×x16 + 1×x4 slot; or two x8/x8 lane split when a second card is installed Read board manual; check lspci -vv | grep LnkSta. May require BIOS bifurcation toggle
b cudaDeviceCanAccessPeer returns false All slots share one root port and ACS forces upstream redirection; or different IOMMU groups Check lspci -vvv | grep ACSCtl; consider ACS override patch (dev only); or rewire to a PLX-switched server board
c Cold model load takes 30+ s BIOS Resizable BAR / Above 4G Decoding off Enable in BIOS, verify with nvidia-smi -q | grep -A2 BAR1
d Periodic stutter under light load ASPM L1 substate aggressive power saving putting links to sleep Kernel: pcie_aspm=off or per-device tuning
e "Second GPU is dead" / not detected Power: USB-C PD, NVMe, second GPU all share one 12V rail; PSU droops under transient Better PSU, separate rails per GPU, dedicated 12V-2x6 / EPS pigtails
f P2P latency huge, topo -m shows PHB or NODE Slot is on PCH-attached lanes, traffic hops chipset DMI Move the card to a CPU-direct slot; if none, accept it or change platform
g Massive thermal throttling on second card Two flow-through-cooled cards stacked; second card breathes first card's exhaust Riser cable, bigger gap, or blower-style cards

What "the right hardware" actually buys you

Honest advice

If you've outgrown one consumer GPU, the next jump is either a single workstation card with much more VRAM (RTX PRO 6000 Blackwell, 96 GB) or moving to a workstation/server platform with proper lane split. Bolting a second consumer GPU onto a desktop ATX board to do TP is technically possible and almost always disappointing.

11

Interactive: PCIe Topology Lint

Configure a hypothetical box. The lint tool reports per-GPU effective lanes, whether P2P will work, an estimated TP scaling factor, and the warnings you'd hit at deployment time.

Effective lanes/GPU
—
P2P feasible
—
TP scaling (est.)
—
Warnings
—
Reading the result

The TP scaling estimate is a heuristic, not a benchmark. Real numbers depend on model size, batch, and kernel choice. The lint's value is in the warnings: if it complains, you have a real problem to fix before you measure anything.