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.
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
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.
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, 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.
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).
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 · 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.
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.
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.
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.
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.
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.