SERIES Part 1 Part 2 Part 3 Part 4 Part 5 Part 6 Part 7 Part 8 Part 9 Part 10
AMD Field AI Enthusiast · by Pradeep Nallimelli · Part 6 of 10+ · May 2026

The verdict.
Three runtimes, one card, one workload.

Six parts in, the Radeon AI PRO R9700 has been benched on vLLM, on llama.cpp Vulkan, on llama.cpp HIP, and now on SGLang. This is the close of the series — the numbers side by side, the runtime that wins each phase, and the one tuning gap that would change the ranking.

SGLang single stream44
tok / sec on Qwen3-Coder-30B-A3B AWQ-native — clean, untuned MoE kernel.
SGLang at N=16252
aggregate tok / sec — scales linearly to N=8, hits a TTFT cliff at N=16.
Runtimes proven3
vLLM, llama.cpp, SGLang — all running production-grade on a 32 GB workstation card.
Method

The same model class across every test

Every runtime on this slide ran a Qwen3-30B-A3B model (same architecture, same expert count, same 3B active parameters per token). vLLM and SGLang used 4-bit AWQ packings; llama.cpp used the UD-Q4_K_XL GGUF that the unsloth team published. All four stacks ran on the same R9700 with ROCm 7.2.1 on the same host, within the same week.

RuntimeModel packagingQuant kernelNotes
vLLM 0.16cyankiwi AWQ-4bit (CT-format)moe_wna16Production baseline, Part 2
llama.cpp Vulkanunsloth UD-Q4_K_XL GGUFRADV computeDecode champion, Part 3
llama.cpp HIPunsloth UD-Q4_K_XL GGUFrocBLASPrefill champion, Part 4
SGLang v0.5.12 + RDNA4mattbucci Coder-30B-A3B AWQ-nativemoe_wna16 (untuned)This part

SGLang ran with sglang.bench_serving, random-input 256 / random-output 256, concurrency sweep at N = 1, 4, 8, 16. The full bench log is teed to /home/amd/pradeepn/sglang_r9700/logs/bench_*.log.

SGLang on R9700

Scaling clean to N=8, hitting a ceiling at N=16

Output token throughput across concurrency

Source: SGLang v0.5.12 + RDNA4 patches, Qwen3-Coder-30B-A3B AWQ-native, sglang.bench_serving random 256/256, 1× R9700 32 GB, ROCm 7.2.1, 2026-05-29. Untuned MoE kernel config.
ConcurrencyOutput tok/sTotal tok/sMean TPOT (ms)Mean TTFT (ms)
N = 144.373.862.9489
N = 4134.6284.170.0427
N = 8234.2493.985.8526
N = 16252.4580.297.34,082
The TTFT cliff

Where the wheels start to come off

Output throughput climbs cleanly from N=1 through N=8 — roughly linear scaling per stream — and then flattens between N=8 and N=16. The same range shows a tearaway in time-to-first-token: 489 ms at N=1, 526 ms at N=8, and 4,082 ms at N=16.

Mean time-to-first-token (lower is better)

Same bench harness as previous slide.

That cliff is the prefill queue saturating against an MoE kernel that has no tuned config for R9700. The server log called it out at boot — Using default MoE kernel config. Performance might be sub-optimal. Output decode survives because it dispatches narrow shapes that even an untuned kernel handles well. Prefill is where the missing tuning costs real latency.

Cross-runtime

All three stacks on one chart

Single-stream decode throughput, Qwen3-30B-A3B class — tok/s (higher is better)

vLLM: moe_wna16, AWQ; llama.cpp: UD-Q4_K_XL GGUF, -fa 1; SGLang: native AWQ, untuned MoE. 1× R9700, ROCm 7.2.1, 2026-05.

Aggregate throughput at N = 16 — tok/s (higher is better)

llama.cpp omitted — server slot model is not directly comparable to vLLM / SGLang continuous batching.
Verdict

Different runtime for different reason

If you care about...PickWhy
Aggregate throughput at scalevLLM381 tok/s at N=16, the highest number in the series.
Lowest single-stream latencyllama.cpp Vulkan108 tok/s decode, no scheduler overhead.
Highest prefill throughputllama.cpp HIP3,491 tok/s pp512.
Best scheduler features (prefix cache, spec-dec, structured output)SGLang234 tok/s at N=8, even on untuned kernels.

There is no single winner. There is a portfolio. For an agentic deployment that values latency on the first reply and throughput across many parallel agents, the right answer today is vLLM in production with a Vulkan llama.cpp fallback for single-user interactive sessions, and an open path to SGLang once its MoE kernels are tuned for RDNA4.

The opportunity

One tuned config could change the ranking

SGLang's distance from vLLM is not architectural. It is a missing JSON file. The MoE kernel registry already supports R9700; it just has no entry at configs/triton_3_6_0/E=128,N=384,device_name=AMD_Radeon_AI_PRO_R9700,dtype=int4_w4a16.json. Writing that entry is a tuning sweep, not a kernel-rewrite, and a tuned config would close most of the gap to vLLM at N=8 and shorten the prefill queue that drives the N=16 TTFT cliff.

FOR THE SGLANG TEAM
Upstream
Merge the 25 RDNA4 patches from the mattbucci fork. Add gfx1200 and gfx1201 to the setup_rocm.py allow-list. Ship a ROCm wheel.
FOR THE AMD KERNEL TEAM
Tune
Run the SGLang MoE tuner against R9700 and publish the resulting config alongside the existing CDNA entries.
FOR US
Repeat
Re-bench SGLang with the tuned config in hand. Re-publish the cross-runtime chart. That is Part 7 territory.
Summary

What six parts taught us about the R9700

DENSE vs MoE
6.8×
Qwen3-30B-A3B beats dense Qwen2.5-14B-AWQ at 51 vs 7.5 tok/s. MoE is the right shape for this card.
vLLM AGGREGATE
381 t/s
N=16 throughput, moe_wna16 kernel, production-ready today.
VULKAN DECODE
108 t/s
Single-stream, ≈ 85% of an RTX 5090 reference on the same model.
HIP PREFILL
3,491 t/s
pp512 throughput — the right pick for RAG-heavy workloads.
SGLANG SCALING
N=8
Clean linear scaling up to 234 tok/s before the untuned MoE cliff appears.
CARDS BUILT FOR
3
vLLM, llama.cpp, SGLang — three runtimes, three real production paths, all on a 32 GB workstation card.

The R9700 is not a research curiosity. It is a complete, multi-runtime inference platform that ships agentic-grade LLM serving from a single workstation slot — and the gap between its current numbers and the tuned-kernel ceiling is small enough to be worth closing.