I tested llama.cpp on my RTX PRO 5000 pair: one 72 GB card and one 48 GB card on a Z890 system (120 GB combined VRAM). The results compare single-card runs, layer splits, and tensor splits for the models listed below, all measured with the same settings.
Both cards are CPU-attached on separate root ports; the inter-GPU route is a PHB hop, no NVLink. Peer-path details and failure modes: GPU-to-GPU Bandwidth on Z890 and the fix guide.
All numbers below are under the 250 W cap (nvidia-smi -pl 250); stock 300 W
will measure faster.
Measurement conditions
- Dates: matrix 2026-09-14/15; every cell from a stored run JSON with its command
line and logs (the † paired cells: verbatim
llama-benchoutput in the repo notes). The two § offload cells were measured 2026-09-20, on a newer checkout than this page’s pinned build — see Table notes. Flash attention on (fa: 1) for all recorded runs. - Kernel booted
intel_iommu=off iommu=off. Tensor split requires a healthy P2P path: if multi-GPU output is token soup, fix the platform first (guide) —nvidia-smi topo -p2preportsOKeven when DMA is broken; a clean kernel log and stable output are the real evidence. GGML_CUDA_P2P=1is not required post-fix; it was exported for most runs for protocol consistency and results are identical without it.- Repetitions:
-r 5unless noted. Noise envelope: tg reproduces within ~1% across sessions; pp does not. Expect pp drift up to ~10% between sessions, and pp512 on big multi-GPU models swings hard even inside one session (five-r 5samples of 122B tensor3/2read 1208–1669 in a single run). Compare pp only within one session; quote tg across sessions.
Results
| Model | Params | File size | Placement | pp512 (t/s) | pp2048 (t/s) | pp8192 (t/s) | tg128 (t/s) |
|---|---|---|---|---|---|---|---|
| Qwen3.8 27B Q8_0 | 27 B dense | 27.1 GiB | 1×72 | 2275.9 | 2272.4 | 2206.7 | 38.6 |
| Qwen3.8 27B Q8_0 | 27 B dense | 27.1 GiB | tensor 1/1 | 3002.5 | 2912.4 | 2923.5 | 62.3 |
| Qwen3.8 27B Q8_0 | 27 B dense | 27.1 GiB | layer 1/1 | 2476.7 | 3510.6 | 3746.5 | 39.3 |
| Muse Glimmer 30B Q8_0 | 27.9 B | 27.6 GiB | 1×72 | 2677.5 | 2644.6 | 2571.7 | 38.5 |
| Muse Glimmer 30B Q8_0 | 27.9 B | 27.6 GiB | tensor 1/1 | 3241.8 | 3179.4 | 3151.3 | 63.0 |
| Muse Glimmer 30B Q8_0 | 27.9 B | 27.6 GiB | layer 1/1 | 2889.6 | 4231.3 | 4572.4 | 39.2 |
| Gemma 4 31B it Q8_0 | 30.7 B | 30.4 GiB | 1×72 | 2145.5 | 2093.5 | 1987.9 | 33.2 |
| Gemma 4 31B it Q8_0 | 30.7 B | 30.4 GiB | tensor 1/1 | 3022.2 | 2936.0 | 2881.1 | 52.9 |
| Gemma 4 31B it Q8_0 | 30.7 B | 30.4 GiB | layer 1/1 | 2333.7 | 3368.4 | 3617.4 | 33.8 |
| Qwen3.6-35B-A3B Q8_0 | 35 B (3 B active) | 35.2 GiB | 1×72 | 5772.2 | 5547.5 | 5365.6 | 198.0 |
| Qwen3.6-35B-A3B Q8_0 | 35 B (3 B active) | 35.2 GiB | tensor 1/1 | 7492.8 | 6923.9 | 6961.8 | 208.7 |
| Qwen3.6-35B-A3B Q8_0 | 35 B (3 B active) | 35.2 GiB | layer 1/1 | 6138.9 | 8290.6 | 8692.9 | 199.2 |
| Qwen3.5 122B-A10B Q6_K_L | 122 B (10 B active) | 101.3 GiB | tensor 3/2 † | 1234.5 | 2092.1 | 2262.2 | 112.9 |
| Qwen3.5 122B-A10B Q6_K_L | 122 B (10 B active) | 101.3 GiB | layer 3/2 † | 1040.2 | 1758.6 | 2245.9 | 95.3 |
| Nemotron 3 Super 120B-A12B Q6_K | 120 B (12 B active) | 105.8 GiB | layer auto ‡ | 1230.2 | 2133.8 | 2317.1 | 76.5 |
| Laguna S 2.1 Q6_K_L | 118 B (8 B active) | 94.8 GiB | tensor 3/2 † | 1408.4 | 2307.2 | 2356.3 | 127.8 |
| Laguna S 2.1 Q6_K_L | 118 B (8 B active) | 94.8 GiB | layer 3/2 † | 1234.0 | 1826.8 | 1940.0 | 109.2 |
| Qwen3.8 Flash Next Q6_K | 177 B (3 B active) | 156.6 GiB | layer 3/2 ‡ | 441.0 | 493.8 | 498.9 | 82.3 |
| DeepSeek V4 Flash 0731 MXFP4 | 284 B | 145.63 GiB | layer 4.5/2 + -ncmoe 11 § | 52.2 | 203.9 | 217.3 | 19.4 |
| DeepSeek V4 Flash 0731 MXFP4 | 284 B | 145.63 GiB | tensor 3/2 + -ncmoe 12 § | 27.3 | 53.6 | 54.7 | 17.7 |
Table notes
- Placement notation.
1×72= whole model on one card (the 72 GB card, unless stated otherwise);tensor a/b/layer a/b=-sm tensor|layer -ts a/b, the GPU0/GPU1 weight ratio — bare-sm tensoris1/1;layer auto= llama.cpp’s own layer balancer. On this pair the balancer’s allocation came out at roughly3/2: on both 122B and Laguna,layer autoand explicit-ts 3/2agreed within 0.2%. - The same
-tsnumbers do not mean the same thing in both modes. In layer mode they weight whole-layer assignment — a layer goes to this card or that one; in tensor mode they slice the weights inside every tensor, so each card holds part of everything. The flag looks identical and the layout is not, which is why the § rows carry different-tsand-ncmoevalues per mode. - Repetitions. Cells are means of 5 repetitions (
-r 5) except the rows marked † and §: those are single runs. The † pairs were measured back-to-back in one session at matched-ts 3/2, so each † pair is directly comparable to its partner. The § cells are single runs at the settings each mode needs; the § note below says how those settings were arrived at. - Bold tg marks the fastest placement for that file on this box. It is split guidance for these weights, not a ranking of the models.
- ‡ = this llama.cpp build has no tensor mode for that architecture, so no
tensor row exists: b10941 refuses Nemotron 3 Super with
LLAMA_SPLIT_MODE_TENSOR not implemented for architecture 'nemotron_h_moe', and Flash Next the same way forqwen4exp. Those rows are layer placement on the same build — feature gaps in the build, not hardware problems. On Nemotron,layer autoand a biased layer split tied (76.5 vs 76.4 t/s). - § — weights partly in system RAM. DeepSeek V4 Flash 0731 MXFP4 is 145.63 GiB
against 118.39 GiB of VRAM on both cards (72,830 + 48,403 MiB), so running it
means putting some experts in system RAM:
-ncmoekeeps “the Mixture of Experts (MoE) weights of the first N layers in the CPU” — that flag’s own help text. From there the settings were adjusted by hand, mode by mode, down to the smallest offload that fits. In this file the expert tensors are 3.19 GiB per layer (43 layers, 256 routed experts, 6 used plus 1 shared per token), so-ncmoe 11leaves ≈ 110.6 GiB of weights on the cards and-ncmoe 12≈ 107.4 GiB; whatever stays in RAM is read over PCIe on every generated token. Layer split fits at4.5/2with-ncmoe 11, tensor split at a flatter3/2with one more layer in RAM. Within those settings layer wins both phases — pp8192 217.3 vs 54.7 t/s, about ≈ 38 s versus ≈ 150 s to read an 8k prompt, and 19.4 vs 17.7 t/s at tg128 — the reverse of every resident file in this table. The figures belong to this offload layout, so they sit apart from the resident rows above.llama-benchlabels the architecturedeepseek4 ?B, so there is no active-parameter count for the Params column; sizes and the layer and expert counts come from the GGUF’s own tensor table. Measured 2026-09-20 on this tree’s CUDA build, which reports b11063 (3d82ef62d) — also where-ncmoeand the availability of tensor split fordeepseek4were read from source. - Which rows share a session. The three Qwen3.8 27B rows and the
Qwen3.6-35B-A3B
1×72row are from the 2026-09-14 session. Muse Glimmer 30B and Gemma 4 31B1×72+ tensor1/1rows, and the Qwen3.6-35B-A3B split rows, are from 2026-09-15 sessions; those models’ layer1/1rows come from a second 2026-09-15 session that also re-ran their tensor1/1splits, so the layer-versus-tensor comparison above is same-session for all three dense models. Rows from different sessions are still the same build, hardware and settings — tg reproduces within ~1%, pp much less (see Measurement conditions). - Capacity versus throughput. Muse Glimmer 30B and Gemma 4 31B each fit one
card outright (27.6 / 30.4 GiB), so their tensor
1/1gains are throughput, not capacity. The ~95–101 GiB files are the opposite case: an even split would ask the 48 GB card to hold 47.4–50.7 GiB of weights before KV cache, compute buffers and driver overhead, which is why those rows are3/2.
Laguna S 2.1 placement notes
- Capacity dictates the ratio: the 94.8 GiB Q6_K_L cannot halve onto the
48 GB card, so
3/2(56.9 + 37.9 GiB) is the natural split — and the default layer balancer empirically lands at ~3/2on this pair anyway (auto and explicit3/2agreed within 0.2% on both 122B and Laguna). - Read the loader’s per-device buffer lines on asymmetric cards: they are what separates an allocation problem from a fault. Earlier quants of this model hit a balancer quirk that looked like a hardware failure; on Q6_K_L the buffers are clean.
llama-benchlabels-Q6_K_Lshards as plainQ6_K(laguna 118B.A8B Q6_K, 94.83 GiB / 117.56 B params). Quote filenames, notmodel_type.- Laguna ships as three GGUF shards; point
-mat shard 00001 and the rest load automatically.
Commands
llama.cpp b10941 (4a8993735) for the table, except the two § DeepSeek V4 Flash rows,
run from a newer checkout whose build reports b11063 (3d82ef62d); adjust paths to
your tree.
# build
cmake -B build-cuda -DGGML_CUDA=ON && cmake --build build-cuda -j
BIN=~/src/llama.cpp/build-cuda/bin
# single-GPU control (repeat per card with --device CUDA0 / --device CUDA1)
$BIN/llama-bench -m ~/models/Qwen3.8/Qwen3.8-27B-Q8_0.gguf \
--device CUDA0 -sm none -p 512,2048,8192 -n 128
# matched-ratio pair (same session; auto layer balancer picks ~3/2 on this box anyway)
$BIN/llama-bench -m ~/models/Qwen3.5/Qwen_Qwen3.5-122B-A10B-Q6_K_L/*.gguf \
-sm layer -ts 3/2 -p 512,2048,8192 -n 128
$BIN/llama-bench -m ~/models/Qwen3.5/Qwen_Qwen3.5-122B-A10B-Q6_K_L/*.gguf \
-sm tensor -ts 3/2 -p 512,2048,8192 -n 128
# Laguna matched pair (same session; run back-to-back)
$BIN/llama-bench -m ~/models/Laguna/Laguna-S-2.1-Q6_K_L/*00001-of-00003.gguf \
-sm tensor -ts 3/2 -p 512,2048,8192 -n 128
$BIN/llama-bench -m ~/models/Laguna/Laguna-S-2.1-Q6_K_L/*00001-of-00003.gguf \
-sm layer -ts 3/2 -p 512,2048,8192 -n 128
# DeepSeek V4 Flash MXFP4: bigger than both cards, so the first N layers'
# experts stay in system RAM (-ncmoe). Single repetition each.
$BIN/llama-bench -m ~/models/DeepSeek-V4-Flash-0731-MXFP4/*00001-of-00004.gguf \
-sm layer -ts 4.5/2 -ncmoe 11 -r 1 -p 512,2048,8192 -n 128
$BIN/llama-bench -m ~/models/DeepSeek-V4-Flash-0731-MXFP4/*00001-of-00004.gguf \
-sm tensor -ts 3/2 -ncmoe 12 -r 1 -p 512,2048,8192 -n 128
Common flags for the table cells: -ngl 999 -b 2048 -ub 512 -fa on -ctk f16 -ctv f16.
Two syntax notes, because they differ between programs:
llama-benchseparates devices inside one split with/(or;); a comma starts a separate benchmark variant, so-ts 1,1runs two single-GPU benches rather than one split run.llama-server/llama-cliaccept either character as the device separator, so the same model placed here with tensor3/2runs as:
llama-server -m model.gguf --split-mode tensor --tensor-split 3,2 \
-ngl 999 -fa on -ctk f16 -ctv f16
Details and the source check behind both: llama.cpp Common Options.