Cited multi-user serving · llama.cpp first

Serving many users on two Radeon cards: what works in 2026

Several clients on one or two Radeon AI PRO R9700 cards is a llama.cpp problem first. On one GPU, llama-server -np / --parallel plus continuous batching already scales. On two GPUs, the documented default is --split-mode layer (pipeline). --split-mode tensor is experimental. vLLM TP=2 and the Radiance engine can raise aggregate tok/s under load, and they carry gfx1201 bugs and format limits. Third-party numbers stay labeled. Our lab cells are the house 35B and Flash pair. UD-Q3_K_XL is a labeled estimate (Hugging Face listing for Qwen3.6-35B-A3B-UD-Q3_K_XL.gguf (16.8 GB)). Q1/Q2 stay off.

The 30-second answer

llama.cpp handles concurrent requests well on one GPU. A third-party Strix Halo shootout (Qwen3.6-35B-A3B UD-Q4_K_M) saw aggregate tok/s climb from 58.8 at 1 slot to 189.7 at 16 on Vulkan, and from 48.6 to 207.8 on a Lemonade ROCm build. Per-token latency rose with load: Vulkan p95 inter-token latency went from 16.2 ms to 81.9 ms. That is third-party, not an AMDai R9700 card. What llama.cpp lacks is fast multi-GPU serving. Puget’s third-party 2× R9700 layer-split run (Qwen3.6-27B Q4_K_M, --parallel 8) flattened at about 56 tok/s from 4 to 8 users. The same article’s vLLM TP=2 stock build went from 15.88 tok/s at 1 user to 156.21 at 8. Try vLLM or Radiance when a model does not fit one card and you need tensor-parallel throughput on bare metal — not as the daily driver.

Building a two-card box? See the two-R9700 parts list (board with x8/x8 slots, 1200 W PSU, 96 GB DDR5), each part linked to its Newegg search.

Two-card parts list

Building a two-card box? Board with x8/x8 slots, 1200 W PSU, 96 GB DDR5. Each row opens the Newegg search for that part. The GPU row goes to the R9700 buy notes — we do not print a GPU price here.

Two-R9700 build parts with Newegg check-price links
Part Pick Check
GPU Two AMD Radeon AI PRO R9700 (32 GB) R9700 buy notes
Motherboard ASRock X870 Taichi Creator Newegg: check price
CPU AMD Ryzen 9 9900X Newegg: check price
RAM G.SKILL Flare X5 96 GB (2x48) DDR5-5600 CL40 Newegg: check price
PSU Thermaltake Toughpower GT 1200W Newegg: check price
Storage Samsung 990 PRO 4TB (MZ-V9P4T0BW) Newegg: check price
Case Fractal Design Torrent Newegg: check price
Cooler Noctua NH-D15 G2 Newegg: check price

As an Amazon Associate I earn from qualifying purchases. Some Newegg links use Rakuten Advertising and some B&H links use B&H’s affiliate program when those IDs are configured. Micro Center and AMD Store links are plain “also available at” links — no tracking. Buttons say “Check price” and never invent or live-quote a price. Full disclosure.

Our lab measurements

These two cells are AMDai first-party numbers. They are one-client or Flash-pair cards, not a 16-user serving table.

llama.cpp first: flags that work today

Start with one llama-server. Official -np / --parallel sets slot count (default -1 = auto; env LLAMA_ARG_N_PARALLEL). Continuous batching (-cb) is on unless you pass --no-cont-batching. GET /health prints total_slots. Usable context per client is total ctx / np unless you raise -c or set --kv-unified-per-slot. House daily driver stays -np 1 until several clients share the unit. Shopper flags for two cards are --split-mode layer (default, best batch throughput) and --split-mode tensor (experimental, aims at lower single-stream latency). Official docs: pipeline-parallel maximizes batch throughput; tensor-parallel minimizes latency. Tensor mode needs flash attention, an unquantized KV cache, and no --fit. Only CUDA is optimized. ROCm works through HIP. Vulkan tensor split is still an open PR. Tensor mode is not available on Windows (no P2P).

Stay on llama.cpp when the GGUF fits one 32 GB card, when you want the widest model list, or when gfx1201 has to stay boring. Raise -np on one process when Open WebUI, Hermes, and a phone share one unit. Pin one llama-server per card behind a router when two copies of a model that already fits beat a split — that is the measured /qwen36-dual layout. Try vLLM TP=2 on bare metal with NCCL_PROTO=Simple when you need continuous batching plus tensor parallel on a dense ~27B that does not fit one card, and you can live with FP8 (GGUF is an experimental plugin). Try Radiance when you want an Apache-2.0 C++/HIP server written for two 32 GB R9700s, you can convert off GGUF, and the architecture is on its curated list. Do not start a private vLLM gfx1201 fork — the deprecated vllm-radiance tree is the cautionary tale.

# One interactive user on one R9700 (house daily driver).
# llama-server README: -np / --parallel N (default -1 = auto, four slots).
# Default idle-slot save copies empty slots on each new task (slow path on Radeon).
# Keep -np 1 for a single-user lane so those empty slots do not stall the stream.
./build-vk/bin/llama-server \
  -m /path/to/nvme/Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf \
  -ngl 99 -c 262144 --cache-type-k f16 --cache-type-v f16 --jinja \
  -np 1 --host 127.0.0.1 --port 8080
# Shared server on one GPU: size per-slot context first.
# Official --kv-unified-per-slot N is the context limit per slot.
./build-vk/bin/llama-server \
  -m /path/to/nvme/Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf \
  -ngl 99 --kv-unified-per-slot 32768 -np 4 \
  --cache-type-k f16 --cache-type-v f16 --jinja \
  --host 127.0.0.1 --port 8080
# Two cards, pipeline split (documented default).
# llama.cpp multi-gpu.md: layer maximizes batch throughput.
./build-hip/bin/llama-server \
  -m /path/to/nvme/Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf \
  -ngl 99 -c 32768 --split-mode layer --parallel 8 \
  --cache-type-k f16 --cache-type-v f16 --jinja \
  --host 127.0.0.1 --port 8080
# Two cards, experimental tensor split. CUDA is the optimized path.
# Requires flash attention, unquantized KV, and no --fit.
./build-hip/bin/llama-server \
  -m /path/to/nvme/Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf \
  -ngl 99 -c 32768 --split-mode tensor -fa on \
  --cache-type-k f16 --cache-type-v f16 --parallel 4 --jinja \
  --host 127.0.0.1 --port 8080

Two ways to split a model across two GPUs

Pipeline (layer) split parks some layers on GPU 0 and the rest on GPU 1. One user’s decode still waits on both cards in sequence, so a single stream does not get faster. Extra users can fill the idle card, which is why layer split is the throughput layout. Tensor (row / experimental tensor) split cuts each layer across both cards and all-reduces activations. That can cut single-stream latency when the interconnect and all-reduce are healthy. On this desktop the cards sit on PCIe 5.0 x8/x8. Puget’s third-party P2P bandwidth on 2× R9700 was 27.6 GB/s. RCCL hangs under KVM/VFIO in that article and works on bare metal. A GPU behind the chipset (no PCIe atomics) breaks RCCL.

Pipeline (layer)

Some layers on GPU 0, the rest on GPU 1. One user waits on both cards in sequence, so a single stream does not get faster. Extra users can fill the idle card. This is --split-mode layer, the documented default.

Tensor (experimental)

Each layer is cut across both cards, then an all-reduce. That can cut single-stream latency when P2P and AllReduce are healthy. --split-mode tensor needs flash attention and f16 KV. CUDA is the optimized path.

Engine status board

Last checked 2026-10-28. Cells paraphrase cited docs plus house rules. Third-party speed cells stay on the figures list below.

Serving gap on 1–2 Radeon cards. llama.cpp first. Last checked 2026-10-28.
Need llama.cpp Strata vLLM (ROCm) Radiance
GGUF Q4–Q6 served directly Yes Yes (own packs; many sit below Q4) Plugin; docs call it experimental Convert only
Single-GPU continuous batching Yes (-np + -cb) Opt-in since 0.1.39 (Oct 2026) Yes Yes (up to 32 sequences)
Multi-GPU throughput under load Layer split plateaus (third-party ~56 tok/s at 4–8 users) Pipelined groups TP=2 (fragile on gfx1201) TP=2
Multi-GPU latency (TP) on HIP Experimental tensor; unquantized KV only No (pipeline only) Yes, with open RCCL / AITER / Triton bugs Yes
Vulkan tensor parallel Open PR #25051 (2-device) Not applicable Not applicable Not applicable
Stability on gfx1201 House daily driver Maintainer-tested HIP RCCL / AITER / Triton bugs Young project (repo 2026-09-25)
Model breadth Widest GGUF list Narrow showcase list Wide, not GGUF-first Curated architectures

Cited third-party figures

Every number below is third-party. Each cell links to its source and the date we checked it. None of these are our lab.

Third-party serving figures, each linked to its source. Checked 2026-10-28.
What Figure Source
Third-party · Strix Halo Vulkan · Qwen3.6-35B Q4_K_M · np 1→16 58.8 → 96.1 → 138.8 → 170.9 → 189.7 tok/s S-CSV checked 2026-10-28 · measured 2026-05-05
Third-party · Strix Halo ROCm (Lemonade) · same file · np 1→16 48.6 → 82.2 → 127.0 → 177.2 → 207.8 tok/s S-CSV checked 2026-10-28 · measured 2026-05-05
Third-party · Strix Halo Vulkan p95 inter-token latency · np 1→16 16.2 → 81.9 ms S-CSV checked 2026-10-28 · measured 2026-05-05
Third-party · Puget 2× R9700 llama.cpp layer · Qwen3.6-27B Q4_K_M · c=1/4/8 23.4 / 55.7 / 56.0 tok/s (TTFT 2,668 ms at c=8) S-PUGET checked 2026-10-28 · published 2026-08-18, modified 2026-09-10
Third-party · Puget 2× R9700 vLLM 0.20.2 FP8 TP=2 · c=1/4/8 15.88 / 69.34 / 156.21 tok/s S-PUGET checked 2026-10-28 · published 2026-08-18, modified 2026-09-10
Third-party · Puget tuned vllm-radiance · c=1/4/8 32.0 / 110.6 / 198.8 tok/s S-PUGET checked 2026-10-28 · published 2026-08-18, modified 2026-09-10
Third-party · Puget tuned + MTP · c=1/4/8 62.8 / 186.3 / 320.2 tok/s S-PUGET checked 2026-10-28 · published 2026-08-18, modified 2026-09-10
Third-party · Puget 2× R9700 measured P2P bandwidth 27.6 GB/s S-PUGET checked 2026-10-28 · published 2026-08-18, modified 2026-09-10
Third-party · 2× R9700 ROCm 7.2.4 · Qwen3-27B Q8_0 tg128 1 GPU 19.50 → stock TP 28.30 → P2P AllReduce 30.43 tok/s S-25197 checked 2026-10-28 · 2026-07-01
Third-party · 2× R9700 ROCm 7.2.4 · Bielik-11B Q8_0 tg128 45.09 → 55.06 → 61.22 tok/s S-25197 checked 2026-10-28 · 2026-07-01
Third-party · HIP AllReduce · RX 6800 XT + RX 9070 · gemma4 31B Q6_K pp +15.9%, tg +2.2% S-27825 checked 2026-10-28 · merged 2026-09-15
Third-party · SYCL TP template · dual Arc Pro B70 · 70B Q4_K_M tg 17.40 vs 9.74 layer (+78.6%) S-B9788 checked 2026-10-28 · 2026-06-25
Third-party · Vulkan MoE batch cliff fix (closed 2026-10-15) +56% at B=9, +34% at B=16 after raising thresholds S-25356 checked 2026-10-28 · 2026-07-06, closed 2026-10-15
Third-party · Strata pipeline windows · 2× R9700 decode 103 → 125 tok/s S-STRATA-MGPU checked 2026-10-28 · read 2026-10-28
Third-party · Strata batching · 2 GPUs, 8 clients 109 vs 78 tok/s S-STRATA-BATCH checked 2026-10-28 · read 2026-10-28
Third-party · Strata batching · 4× R9700, 8 clients 166 vs 86 tok/s S-STRATA-BATCH checked 2026-10-28 · read 2026-10-28
Third-party · Strata · 16 slots on 4× R9700 324 tok/s S-STRATA-BATCH checked 2026-10-28 · read 2026-10-28
Third-party · Strata --batch-mtp · 2× R9700 80.2 → 62.7 tok/s S-STRATA-BATCH checked 2026-10-28 · read 2026-10-28
Third-party · Level1Techs · Llama-3.1-8B BF16 on R9700 38.1 tok/s TP1, 65.1 tok/s TP2 S-L1T checked 2026-10-28 · 2026-05-22
Third-party · Level1Techs · Qwen3.6-35B-A3B-FP8 17.2 tok/s TP2, 15.6 tok/s TP4 S-L1T checked 2026-10-28 · 2026-05-22
Third-party · Radiance · Qwen3.8-27B MXFP4 · 2× R9700 134–140 tok/s at 1 stream, 550–555 at 16 S-RAD-GUIDE checked 2026-10-28 · read 2026-10-28
Third-party · Radiance · TranslateGemma 27B MXFP4 · 2× R9700 56 tok/s per stream, 205 at four S-RAD checked 2026-10-28 · repo created 2026-09-25, updated 2026-10-28
Third-party · community SGLang fork · Qwen3.6-35B-A3B AWQ short context 67.0 tok/s S-SGL-FORK checked 2026-10-28 · sweep 2026-10-19

vLLM TP=2 on R9700

vLLM’s docs list RX 9000 / gfx1200–1201. AMD’s ROCm 10.1 matrix lists the R9700 with vLLM 0.29.0. AMD ships gfx1201 wheels. Puget’s third-party 2× R9700 table (Qwen3.6-27B, 500 in / 200 out) at concurrency 1 / 4 / 8: stock v0.20.2 FP8 TP=2 was 15.88 / 69.34 / 156.21 tok/s; a tuned “vllm-radiance” build 32.0 / 110.6 / 198.8; tuned plus MTP 62.8 / 186.3 / 320.2. Wendell’s third-party 4× R9700 notes: Llama-3.1-8B BF16 38.1 tok/s at TP1 and 65.1 at TP2; Qwen3.6-35B-A3B-FP8 17.2 at TP2 and 15.6 at TP4. That last pair is far below our lab one-card 35B Q5. FP8 MoE on gfx12 landed through Triton. An R9700-tuned config PR is still open. AWQ/GPTQ on AMD is patchy. GGUF moved to vllm-gguf-plugin; the docs call it experimental and under-optimized. The vllm-radiance Docker fork is deprecated.

Strata batching

Strata’s HIP backend lists the R9700 as maintainer-tested. Multi-GPU is layer split — explicitly not tensor parallelism. Pipeline windows took a third-party 2× R9700 decode from 103 to 125 tok/s. Batching is opt-in since 0.1.39 (issue #465: “not planned” on 2026-10-02, shipped 2026-10-04). Up to 8 slots per window; --batch-groups pipelines slot groups across cards. Third-party owner figures: 4× R9700 and 8 clients, 166 vs 86 tok/s; on 2 GPUs, 109 vs 78; 16 slots on 4× R9700, 324 tok/s. --batch-mtp on 2× R9700: 80.2 to 62.7 tok/s. Showcase packs often sit below Q4, so they are not a house recipe. Batch windows have no sampling penalties.

Radiance

Radiance is an Apache-2.0 C++/HIP inference server. Bundled kernels target RDNA4 (gfx1200/1201). Serve flags are written for two 32 GB R9700s. APIs: OpenAI, Anthropic, and llama-server-compatible. Features: --tp 2/3/4/8, up to 32 sequences per step, FP8 / int8 / int4 / MXFP4 KV and weights, MTP/DFlash, and a lossy compressed TP wire (--tp-wire wht6). Published third-party 2× R9700 numbers: Qwen3.8-27B MXFP4 134–140 tok/s at 1 stream and 550–555 at 16; TranslateGemma 27B MXFP4 56 tok/s per stream and 205 at four. The guide notes MoE aggregate decode roughly doubles at batch 8 because routed-expert reads are per token. It does not serve GGUF directly; Q4_K / Q6_K / Q8_0 import through rad-convert for supported architectures. Model support is a curated list. The Codeberg repo was created 2026-09-25.

Other engines

Status paraphrases cited docs. We do not invent a tok/s for rows without a linked figure.

Other serving engines on Radeon / RDNA4. Last checked 2026-10-28.
Engine Radeon / RDNA4 Concurrency / TP Source
SGLang AMD docs list the R9700 and say to disable AITER on Radeon. Upstream issue #30599 (updated 2026-10-28) says the ROCm path is Instinct-only. TP plus radix batching on paper. A community fork with 73 patches runs TP=2 on 2× R9700 and targets single-user; Qwen3.6-35B-A3B AWQ 67.0 tok/s at short context (third-party). S-AMD-SGL checked 2026-10-28
MLC-LLM tensor_parallel_shards on ROCm and Vulkan. Docs reference ROCm 6.x. Vulkan TP has a Windows bug. Tensor parallel yes. S-MLC checked 2026-10-28
ExLlamaV3 Preliminary ROCm support (ROCm 10 only, gfx1100+) since v1.6.0 (2026-10-07). Later fixes for gfx11; TP/shmem fixes landed 2026-10-20. TP plus concurrent scheduling. S-EXL3 checked 2026-10-28
Lemonade Ships llama.cpp ROCm builds. Its vllm-rocm gfx120X build is reported broken on gfx1201 (issues #2302 and vllm-rocm #19). llama.cpp or vLLM wrapper. S-LEMON checked 2026-10-28
Ollama A model that fits one GPU loads on one GPU; otherwise it spreads across GPUs. No tensor parallel. OLLAMA_NUM_PARALLEL (default 1). Slots, no TP. S-OLLAMA checked 2026-10-28

Known pitfalls on R9700

RCCL 7.2.x has no gfx1201 tuning entry, so the LL protocol can deadlock. The third-party workaround is NCCL_PROTO=Simple. The ROCm/rccl Navi4 tuning PR is still open. vLLM issue #40980 (TP=2 deadlock on dual R9700) is still open as of 2026-10-17; a maintainer wrote there is no official AITER support for gfx1201. A GDN Triton miscompile hangs TP≥2 startup for Qwen3.6 and Qwen3-Next. shm_broadcast hangs appear in vLLM ≥0.21.0 on that Level1Techs thread. A GPU behind the chipset fails RCCL. VMs hang RCCL; bare metal is the cited path. Windows has no tensor-mode P2P. Do not copy a one-client 35B tok/s onto an 8-user cell.

What to run, in order

  1. 1 · Cited multi-user serving · llama.cpp first

    Serve several users on one card with -np

    Vulkan llama-server, Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf, f16 KV, loopback :8080. Start at -np 1. Raise -np only when several clients stream at once, and size --kv-unified-per-slot first. Slot tok/s on one R9700 stay not measured here — see /concurrency-ab. Q6/Q5/Q4 first. UD-Q3_K_XL is a labeled estimate.

  2. 2 · Cited multi-user serving · llama.cpp first

    On two cards, prefer copies or layer split

    If the GGUF fits one 32 GB card, two independent llama-server processes beat a split for aggregate tok/s. That is the measured /qwen36-dual soak. --split-mode layer is the documented default when one file must span both cards. It does not speed up one user.

  3. 3 · Cited multi-user serving · llama.cpp first

    Treat --split-mode tensor as an experiment

    PR #19378 merged 2026-04-09. CUDA is the optimized path. HIP works and was slower than layer split on the author’s mixed AMD setups. Requires -fa, f16 KV, and no --fit. Third-party 2× R9700 ROCm tg128: Qwen3-27B Q8_0 19.50 → 28.30 → 30.43 with a P2P AllReduce hack. Windows has no tensor mode.

  4. 4 · Cited multi-user serving · llama.cpp first

    Try vLLM TP=2 only on bare metal

    Worth a try when you need continuous batching plus tensor parallel on a dense file that does not fit one card, and you can run FP8. Set NCCL_PROTO=Simple. Expect open RCCL, AITER, and Triton issues. GGUF is an experimental plugin. The vllm-radiance fork is deprecated.

  5. 5 · Cited multi-user serving · llama.cpp first

    Try Radiance for an R9700-native TP server

    Apache-2.0 C++/HIP, flags written for two 32 GB R9700s, up to 32 sequences, --tp 2. Convert GGUF with rad-convert. Model list is curated. Published third-party 27B MXFP4 numbers are far above llama.cpp layer split — they are not our lab.

  6. 6 · Cited multi-user serving · llama.cpp first

    Do not invent a 16-user tok/s

    Our lab 35B and Flash cells are one-client or first-party Flash pairs. Multi-user tables on this page are third-party and linked. The coming dual-Radeon serving kit ships a harness for 1/2/4/8/16 users, TTFT, inter-token latency, and total tok/s on Q4–Q6 only. No repository is linked yet.

Open project: dual-Radeon serving kit (coming soon)

The dual-Radeon serving kit is an open project, coming soon. Milestone 1 is a thin OpenAI-compatible router in front of one llama-server per card, plus an open benchmark harness. The router will use least-outstanding-tokens balancing with prefix and session affinity so prompt caches stay warm, health checks, and /metrics passthrough. Optional spill will route a model that does not fit one card to a TP or layer-split instance. The harness will drive 1, 2, 4, 8, and 16 concurrent users and record TTFT, inter-token latency, and total tok/s. Weight files stay Q4 through Q6. Engines in the same harness: llama-server on ROCm and Vulkan (1 card, -sm layer, -sm tensor, and 2 replicas plus the router), Strata when a Q4+ pack exists, vLLM ROCm FP8 TP=2 with NCCL_PROTO=Simple, and Radiance FP8 or 4-bit. No public repository is linked yet.

Sources

Every claim on this page links here. Dates are when we checked the URL, plus the source’s own date when it has one.

How we test — Measured cells cite official amdai-bench/run@1 cards. Estimates stay labeled. Q3 is estimate-only. Q1/Q2 stay off.

Next steps

Real pages on this site. We do not invent a next click.

Last updated

esc

Type to filter. Enter opens the first match. Full-text search lives on /search.