TinkerLab
01 // HOMELABNVIDIA GPUDocker / Compose~8 min read & lab

NVIDIA PC Model Loading & VRAM Diagnostics: Spotting PCIe Shared-Memory Spillover

Why a 12GB RTX GPU silently drops from 48 tok/s to 4 tok/s without throwing an OOM error—and how to cross-check nvidia-smi against ollama ps.

[KEY VERIFIED TAKEAWAY / TL;DR]In Tinker AI Lab's reproducible verification of "NVIDIA PC Model Loading & VRAM Diagnostics: Spotting PCIe Shared-Memory Spillover" (tested on NVIDIA RTX 4070 12GB VRAM · 32GB DDR5 System RAM · Ubuntu 24.04 & Windows 11 WSL2 with NVIDIA Driver 560.35 / CUDA 12.6, Ollama 0.5.7, nvidia-container-toolkit 1.16.2, verified 2026-10-23): Why a 12GB RTX GPU silently drops from 48 tok/s to 4 tok/s without throwing an OOM error—and how to cross-check nvidia-smi against ollama ps. Offline capability is classified as "100% Local GPU Execution" (All diagnostics use local `nvidia-smi` and `ollama ps` queries without external dependencies.), with key operational boundary: Modern NVIDIA drivers enable CUDA Sysmem Fallback by default: exceeding physical 12GB VRAM by even 600MB pages tensors over PCIe into DDR5 RAM, slashing speed 8–10x without crashing.
REPRODUCIBILITY MANIFEST // TESTED SPECS & LIMITS
Last Verified: 2026-10-23
Tested Hardware & OS

NVIDIA RTX 4070 12GB VRAM · 32GB DDR5 System RAM · Ubuntu 24.04 & Windows 11 WSL2

Pinned Stack & Model Versions
NVIDIA Driver 560.35 / CUDA 12.6Ollama 0.5.7nvidia-container-toolkit 1.16.2
Offline & Network Boundary
100% Local GPU Execution

All diagnostics use local `nvidia-smi` and `ollama ps` queries without external dependencies.

Known Limits & Failure Modes
  • Modern NVIDIA drivers enable CUDA Sysmem Fallback by default: exceeding physical 12GB VRAM by even 600MB pages tensors over PCIe into DDR5 RAM, slashing speed 8–10x without crashing.
  • Running an embedding model (`bge-m3`) alongside a 14B Q4_K_M chat model on a 12GB card leaves less than 1.1GB for KV cache, triggering layer spill at num_ctx > 4096.
Hit an edge-case failure?Open Troubleshooter →

1. Cross-Checking `nvidia-smi` vs `ollama ps` to Catch Layer Spillover

When `qwen2.5:14b-instruct-q4_K_M` is loaded at `num_ctx=4096` on an RTX 4070 (12GB), `ollama ps` reports `10.4 GB | 100% GPU` and generates at **46.8 tok/s**. However, if a client (such as Open WebUI or an IDE plugin) requests `num_ctx=32768` with default FP16 KV cache, total memory climbs to **14.9 GB**. Ollama offloads 36 of 48 layers to GPU and keeps 12 layers on CPU (`26% CPU / 74% GPU`), causing generation speed to collapse to **4.9 tok/s**.
Table 1: RTX 4070 (12GB VRAM) Layer Offload & PCIe Spillover Measurements
Workload ConfigurationTotal Memory Neededollama ps SplitMeasured Speed
qwen2.5:7b Q4_K_M @ 16K ctx (f16 KV)6.4 GB100% GPU (28/28 layers)78.5 tok/s
qwen2.5:14b Q4_K_M @ 4K ctx (f16 KV)10.4 GB100% GPU (48/48 layers)46.8 tok/s
qwen2.5:14b Q4_K_M @ 16K ctx (q8_0 KV)11.1 GB100% GPU (48/48 layers)42.1 tok/s
qwen2.5:14b Q4_K_M @ 32K ctx (f16 KV)14.9 GB (Spills +2.9GB)26% CPU / 74% GPU4.9 tok/s (9.5x slower)
Compare Physical VRAM vs Layer Split
# 1. Check how many layers are on GPU vs CPU
ollama ps

# 2. Check physical VRAM saturation and compute utilization
nvidia-smi --query-gpu=name,memory.total,memory.used,memory.free,utilization.gpu --format=csv

2. Fitting 14B on 12GB VRAM & Fixing Docker GPU Passthrough

To keep 14B Q4_K_M 100% inside 12GB VRAM at 16K context: 1. Set `OLLAMA_FLASH_ATTENTION=1` and `OLLAMA_KV_CACHE_TYPE=q8_0` (reduces 16K KV cache from ~2.0 GB to ~1.05 GB). 2. Set `OLLAMA_MAX_LOADED_MODELS=1` so idle models do not fragment VRAM. 3. If running inside Docker on Linux/WSL2, verify `nvidia-container-toolkit` is configured and `deploy.resources.reservations.devices` is present in `docker-compose.yml`.
Configure NVIDIA Container Toolkit & systemd VRAM Environment
# 1. Wire NVIDIA runtime into Docker Engine and restart daemon
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# 2. Verify container can see physical GPU VRAM
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi

3. WSL2 vs Native Linux VRAM Overhead & Desktop Compositor Reserve

On Windows 11 + WSL2, the Windows Desktop Window Manager (`dwm.exe`), multi-monitor 4K framebuffers, and hardware-accelerated browsers consume **0.9–1.6 GB of physical VRAM** before you even start Ollama. On a headless Ubuntu 24.04 server without X11/Wayland, baseline VRAM usage is under **80 MB**. That extra 1.2 GB of headroom is often the exact difference between fitting `qwen2.5:14b` at 16K context on a 12GB card vs spilling 4 layers to system DDR5 RAM.
FIELD Q&A // 常见实测疑问与边界解答

Frequently Asked Questions & Edge Cases

Q: Why does Windows Task Manager show "Shared GPU Memory" increasing when speed drops?

"Shared GPU Memory" is regular DDR4/DDR5 system RAM accessed over the PCIe bus (~32 GB/s vs 504 GB/s GDDR6X). In NVIDIA Control Panel -> Manage 3D Settings -> CUDA - Sysmem Fallback Policy, you can disable shared memory fallback if you prefer an immediate OOM error over silent 10x slowdown.

Q: How do I force Ollama to use only one specific GPU on a multi-GPU PC?

Set `CUDA_VISIBLE_DEVICES=0` (or the UUID shown in `nvidia-smi -L`) in the Ollama service environment. Using the GPU UUID (`GPU-xxxxxxxx-...`) prevents device index shifts after driver updates or PCIe slot changes.

REPRODUCIBLE ARTIFACT // 配套可参数化附件

NVIDIA PC Model Loading & PCIe Shared-Memory Spillover Probe

Compares physical VRAM usage in nvidia-smi against ollama ps processor split to detect silent CPU/PCIe fallback.

check-nvidia-vram-spill.sh ↗
Edit variables above to update the configuration live
#!/usr/bin/env bash
# Tinker AI — NVIDIA PC Model Loading & VRAM Spillover Diagnostic (Guide #2)
set -euo pipefail

MODEL="qwen2.5:14b-instruct-q4_K_M"
CTX="16384"

echo "=== [1/4] NVIDIA Driver, CUDA & Physical VRAM Baseline ==="
nvidia-smi --query-gpu=name,driver_version,memory.total,memory.used,memory.free --format=csv

echo "=== [2/4] Triggering Model Load ($MODEL @ num_ctx=$CTX) ==="
curl -sS http://127.0.0.1:11434/api/generate -d "{
  \"model\": \"$MODEL\",
  \"prompt\": \"Warmup VRAM allocation check.\",
  \"stream\": false,
  \"options\": { \"num_ctx\": $CTX }
}" > /dev/null

echo "=== [3/4] Inspecting Layer Offload Split (Look for 100% GPU vs CPU/GPU Split) ==="
ollama ps

echo "=== [4/4] Post-Load Physical VRAM Utilization ==="
nvidia-smi --query-gpu=memory.used,memory.free,utilization.gpu --format=csv

More Reproducible Engineering Guides

View All 42 Guides →