Summary
On a system with two Arc Pro B70 (xe driver, kernel 7.0, Level Zero runtime libze_intel_gpu.so.1.15.39122 / intel-opencl-icd 26.27.39122.11, as shipped inside the vllm/vllm-openai-xpu image), any process in which Level Zero can see both GPUs (ZE_AFFINITY_MASK=0,1) consumes approximately 1 GiB of host RAM per 1 GiB of device memory it allocates, on either GPU. With a single visible device (ZE_AFFINITY_MASK=0 or 1) the same allocations cost almost no host RAM. The host memory is not attributable to any standard accounting bucket and is released only when the process's DRM contexts are torn down.
This makes multi-GPU serving on modest-RAM hosts fail: loading a 29 GiB FP8 model across two 32 GB B70s through two worker processes (each seeing both GPUs, as vLLM configures them) exhausts 30 GiB of host RAM, while the identical load with per-process single-device visibility succeeds with ~2 GiB of host overhead.
Reproducer (~60 s, no files read, no host->device copies)
Run in any torch-xpu container (--device /dev/dri -v /dev/dri:/dev/dri:ro), then watch host /proc/meminfo MemAvailable while the process holds the tensors:
docker run --rm --device /dev/dri -v /dev/dri:/dev/dri:ro \
-e ZE_AFFINITY_MASK=0,1 \
--entrypoint python3 <torch-xpu image> - <<'EOF'
import torch, time
ts = []
for i in range(10): # 10 GiB of device memory on xpu:0
t = torch.empty(1 << 30, dtype=torch.uint8, device="xpu:0")
t.zero_() # commit pages on device; no host->device copy
ts.append(t)
print("HOLDING") # inspect host /proc/meminfo NOW
time.sleep(60)
EOF
Measured matrix (host MemAvailable delta while tensors held)
| Process visibility |
Device memory held |
Host RAM cost |
Ratio |
ZE_AFFINITY_MASK=0 (1 GPU visible) |
5.6 GiB (GPU0) |
0.77 GiB |
~0.14 (process overhead) |
ZE_AFFINITY_MASK=0,1 |
10.8 GiB (GPU0) |
10.59 GiB |
0.98 |
ZE_AFFINITY_MASK=0,1 (+ZE_FLAT_DEVICE_HIERARCHY=COMPOSITE) |
11.0 GiB (GPU0) |
10.97 GiB |
1.00 |
2 processes, masks 0 and 1 |
10.5 GiB (both GPUs) |
0.82 GiB |
~0.08 |
All allocations landed on GPU 0 in the affected runs (GPU 1 nearly untouched), so the cost tracks device-memory allocations, not per-device context creation.
Forensics (while 10.9 GiB VRAM held under mask 0,1)
- Worker RSS (VmHWM): <= 2.6 GiB — the host memory is not process anonymous memory.
AnonPages 121 MiB, Cached 80 MiB, Slab 0.83 GiB, Shmem 4 MiB, VmallocUsed 144 MiB, HugePages_Total 0, Unevictable/Mlocked/VmPin ~0 — no visible bucket accounts for the ~10 GiB; /proc/buddyinfo confirms the pages are genuinely allocated.
- Fully recovered after the container exits (DRM context teardown).
- Reproduces with zero file I/O and with allocations never copied from host buffers (
t.zero_() only), so this is not page cache, not checkpoint staging, not pinned transfer buffers.
Questions
- What kernel/driver structure scales ~1:1 with
zeDriverAllocDeviceMemory when the process sees more than one device?
- Is there a supported way to disable it (environment variable or allocation flag)?
- If intended, could it be documented? Currently it presents like a host-memory leak in every multi-GPU XPU process.
Environment: 2 x Intel Arc Pro B70 (8086:e223), xe KMD, kernel 7.0.0, Level Zero 1.15.39122 / intel-opencl-icd 26.27.39122.11 (pinned inside the vllm-openai-xpu image; newest compute-runtime release not yet re-tested — happy to re-verify on request), docker with --device /dev/dri plus a read-only /dev/dri bind mount, AMD-IOMMU enabled, resizable BAR active (32 GB aperture per card).
Summary
On a system with two Arc Pro B70 (xe driver, kernel 7.0, Level Zero runtime
libze_intel_gpu.so.1.15.39122/ intel-opencl-icd26.27.39122.11, as shipped inside thevllm/vllm-openai-xpuimage), any process in which Level Zero can see both GPUs (ZE_AFFINITY_MASK=0,1) consumes approximately 1 GiB of host RAM per 1 GiB of device memory it allocates, on either GPU. With a single visible device (ZE_AFFINITY_MASK=0or1) the same allocations cost almost no host RAM. The host memory is not attributable to any standard accounting bucket and is released only when the process's DRM contexts are torn down.This makes multi-GPU serving on modest-RAM hosts fail: loading a 29 GiB FP8 model across two 32 GB B70s through two worker processes (each seeing both GPUs, as vLLM configures them) exhausts 30 GiB of host RAM, while the identical load with per-process single-device visibility succeeds with ~2 GiB of host overhead.
Reproducer (~60 s, no files read, no host->device copies)
Run in any torch-xpu container (
--device /dev/dri -v /dev/dri:/dev/dri:ro), then watch host/proc/meminfoMemAvailablewhile the process holds the tensors:Measured matrix (host MemAvailable delta while tensors held)
ZE_AFFINITY_MASK=0(1 GPU visible)ZE_AFFINITY_MASK=0,1ZE_AFFINITY_MASK=0,1(+ZE_FLAT_DEVICE_HIERARCHY=COMPOSITE)0and1All allocations landed on GPU 0 in the affected runs (GPU 1 nearly untouched), so the cost tracks device-memory allocations, not per-device context creation.
Forensics (while 10.9 GiB VRAM held under mask 0,1)
AnonPages121 MiB,Cached80 MiB,Slab0.83 GiB,Shmem4 MiB,VmallocUsed144 MiB,HugePages_Total0,Unevictable/Mlocked/VmPin~0 — no visible bucket accounts for the ~10 GiB;/proc/buddyinfoconfirms the pages are genuinely allocated.t.zero_()only), so this is not page cache, not checkpoint staging, not pinned transfer buffers.Questions
zeDriverAllocDeviceMemorywhen the process sees more than one device?Environment: 2 x Intel Arc Pro B70 (
8086:e223),xeKMD, kernel 7.0.0, Level Zero1.15.39122/ intel-opencl-icd26.27.39122.11(pinned inside the vllm-openai-xpu image; newest compute-runtime release not yet re-tested — happy to re-verify on request), docker with--device /dev/driplus a read-only/dev/dribind mount, AMD-IOMMU enabled, resizable BAR active (32 GB aperture per card).