November 11, 2026
hero-en-performance-showcase
Complete deployment walkthrough for serving a 125B MoE model on two RX 7900 XTX cards: 128K TTFT cut from 41.8s to 22.9s, 5,748 tok/s prefill, full 256K context. Hardware BOM, engine build, expert packing, dual-GPU config and benchmark protocol included.

Dual RX 7900 XTX Deployment Guide: Run a 125B MoE Model with 256K Context at 5,748 tok/s

Test rig: AMD Ryzen 7 3700X · 2 × RX 7900 XTX 24GB (PCIe 4.0 x8 + x8, measured) · 94 GB DDR4 · Ubuntu 24.04.4 · ROCm 7.2.4
Engine: Strata RDNA3 fork (commit e1dad2dc) — tensor-parallel decode, dual-path prefill
Model: Qwen3.8-Flash-Next 125B MoE · Swift IQ3_S (46.8 GB) / Unsloth UD-IQ4_XS (56 GB)

What this is: a complete deployment walkthrough, from a fresh Ubuntu install to a serving endpoint. Every command and config below comes from the real machine — copy them and you should land in the same place.
Who it is for: developers and builders who want a 125B-class model running privately on consumer hardware with long-context agent workloads.
Time: 2–4 hours, most of it model download (engine build is ~15 min).
Prerequisites: comfort with a terminal and a fresh Ubuntu install. That is all.


What you get when you are done

Two consumer cards, no NVLink, no datacenter parts — and the same 125B model running jointly across both. Here is what our reference machine measured after following this guide exactly (3-run median, temp=0):

Metric Single GPU Dual GPU (this guide) Speedup
128K prefill 3,148.4 tok/s 5,748.5 tok/s 1.83x
128K TTFT 41.752 s 22.917 s 1.82x
32K decode 88.6 tok/s 133.7 tok/s 1.51x
256K (261,632 tok) prefill — * 5,766.9 tok/s —

*Single-GPU 256K was not part of this test matrix. You can add it with the protocol in Step 6.

Also: 3/3 needle-in-a-haystack keys recalled at 256K, zero OOM, zero crashes across every round, and a 210.35 tok/s single-request peak in a long-output sweep (speculative-decoding friendly workload, not steady state).

128K prefill: 3,148 tok/s single vs 5,748 tok/s dual

Figure 1 — 128K prefill throughput, same engine build. Dual-card tensor parallelism adds 83%.

Long-output scan: 210.35 tok/s peak at 36K input

Figure 2 — long-output sweep. Peaks come from high speculative-acceptance windows; steady-state decode is the 133.7 tok/s in the table above.

Six steps and a list of pitfalls follow.


Step 1 — Hardware: know the parts list before you spend

For dual-GPU inference the bottleneck is not the CPU. It is bus topology, VRAM, system RAM, and power/thermal headroom.

Part Recommendation What to watch out for
GPUs 2 × RX 7900 XTX 24GB (gfx1100) 24 GB + 384-bit bus each; together they form a 48 GB pool
Motherboard Any board that can do x8+x8 split (X570 / B650 / X670E) The number one failure mode: never put the second card on a chipset (PCH) x4 slot. Cross-card traffic collapses to a quarter of the bandwidth. Both cards must hang off CPU lanes. x8+x8 is enough — that is what our rig actually ran — x4 is what kills it
CPU Ryzen 7 3700X / 5700X / 7700X class No multi-socket Xeon needed: with ~98% expert-cache hit rate, an AVX2-only 3700X still hits 5,700+ tok/s
RAM ≥ 96 GB (64 GB is the floor) IQ3 peaks at 73.91 GB, IQ4 at 83.16 GB — 9 GB is the difference between “comfortable” and “OOM edge”
PSU 1000–1200 W, 80 PLUS Gold or better Two cards at 303 W each under load. Every 8-pin must be its own cable — no daisy-chained splitters
Cooling Case that fits two 3-slot cards, or an open bench Stacked cards cook the top one into thermal throttling; leave 1–2 slot gaps or add intake fans

Two RX 7900 XTX cards installed side by side

Figure 3 — the reference rig: two RX 7900 XTX cards, each on its own PCIe 4.0 slot, with a cooling gap between them.


Step 2 — OS install and dual-GPU verification

Ubuntu 24.04 LTS is recommended (22.04 works too). The kernel’s amdgpu driver is all you need at the OS level. Verify the cards before you build anything:

# Are both cards visible?
lspci | grep -i vga
# Expect two RX 7900 XTX entries

# Check link speed per card (use your own PCI addresses)
sudo lspci -vv -s 03:00.0 | grep LnkSta
sudo lspci -vv -s 0c:00.0 | grep LnkSta
# Look for: LnkSta: Speed 16GT/s, Width x16 or x8
# x8+x8 is fine (our rig ran GEN 4 @ 8x and still hit 1.83x)
# If you see Width x4 or Speed 8GT/s, fix the BIOS split before going further

# Monitoring tools
sudo apt install -y rocm-smi build-essential git
rocm-smi   # should list GPU0 and GPU1

ROCm note: the engine’s build script installs the ROCm components it needs into a private virtualenv, so you do not have to pre-install ROCm. If your distro requires a system install, use AMD’s official repository for rocm-hip-sdk rocm-smi hipblaslt, then sudo usermod -a -G render,video $USER and log back in.


Step 3 — Build the Strata RDNA3 engine

Two paths, and they are not equivalent. Upstream Strata (MIT, open source) has a ./setup.sh that supports multiple cards, but its default multi-GPU mode is a pipeline layer split — it will not reproduce the numbers in this article. To replicate them you need the RDNA3-focused fork, which adds tensor-parallel decode and a dual-path prefill pipeline for gfx1100:

mkdir -p ~/AI/strata-rdna3-test && cd ~/AI/strata-rdna3-test

# Clone the fork and check out the exact commit we measured against
git clone --branch rdna3 https://github.com/nicejunjie/Strata-rdna3.git fork
cd fork
git checkout e1dad2dc     # the commit behind every number in this post (AVX2-safe on Zen 2)

# One-shot build: pinned toolchain (ROCm / rocWMMA / llama.cpp) + gfx1100 engine
D="$HOME/AI/strata-rdna3-test/data"
mkdir -p "$D"
./setup.sh --setup --build --backend hip --family qwen --model IQ3_S \
  --vision cpu --data-dir "$D" --no-start --yes

# Verify the artifact: backend must be hip, archs must include gfx1100
cat engine/BUILD.json

The build takes 10–20 minutes and you only run it once. It compiles the engine for your card’s architecture, so a git pull that touches the engine means rebuilding.


Step 4 — Download the model and pack the experts

The trick to running a 125B MoE model at these speeds is not just quantization — it is packing the expert weights into a binary layout the engine can stream efficiently.

Pick one model:

Model Packed size Best for Peak host RAM
ukisai/Swift-1.5-Qwen3.8-Flash-Next-GSQ-RCO-GGUF (IQ3_S) — recommended 46.8 GB Chat, fastest generation 73.91 GB
Qwen3.8-Flash-Next-UD-IQ4_XS (Unsloth, 3 shards) 56 GB Code, math, precision-sensitive work 83.16 GB
cd ~/AI/strata-rdna3-test/fork
D="$HOME/AI/strata-rdna3-test/data"

# Download both IQ3_S shards from Hugging Face (or hf-mirror.com for resumable
# downloads inside mainland China) into $D/models/swift-IQ3_S/.
# Both shards are required; download size follows the model card.

# Build the expert pack (~46.8 GB experts.bin)
export STRATA_GGUF_PY="$PWD/third_party/llama.cpp/gguf-py"
.venv/bin/python tools/iq_pack.py \
  --gguf "$D/models/swift-IQ3_S/Swift-Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf" \
  --out "$D/packs/swift-iq3_s" --experts-bin

# Confirm the artifact
ls -lh "$D/packs/swift-iq3_s/experts.bin"

Step 5 — Dual-GPU config and launch

In one sentence, here is what this configuration does: --tensor-parallel 2 splits the weight matrices so both cards compute half of every layer, exchanging partial results over PCIe once per layer. This is not “two models in two windows” — it is one model, two cards, working on the same token stream. Long prompts additionally use data-parallel and tensor-parallel prefill paths; that combination is what lifts 128K prefill from 3,148 to 5,748 tok/s.

Config rdna3/configs/swift-iq3-2gpu.json (key fields annotated):

{
 "exe": "@STRATA@/engine/strata",
 "cwd": "@STRATA@",
 "tokenizer": "@DATA@/packs/swift-iq3_s/tokenizer",
 "model_name": "swift-iq3",
 "backend": "hip",
 "gpu": [0, 1],
 "layer_split": "auto",
 "host": "0.0.0.0",
 "port": 18088,
 "open_browser": false,
 "args": [
  "--pack",           "@DATA@/packs/swift-iq3_s",        // expert pack from Step 4
  "--native",         "@DATA@/models/swift-IQ3_S/Swift-Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf",
  "--tensor-parallel", "2",                              // core: split every layer across both cards
  "--prefill",        "auto",
  "--max-context",    "262144",                          // required for 256K (use 131072 for 128K)
  "--kv",             "int8",                            // 8-bit KV cache: what makes 256K fit in 48 GB
  "--kv-resident",    "32768",                           // first 32K stays in VRAM, rest streams via pinned RAM
  "--expert-cache",   "auto",                            // fills both cards' VRAM (the 48 GB saturation)
  "--vram-reserve-mib", "512",
  "--pool-workers",   "8",                               // match CPU cores (3700X = 8)
  "--mtp-q4",         "all",
  "--spec",           "4",                               // speculative decoding window
  "--spec-min-p",     "0.5"
 ],
 "env": {
  "STRATA_HIPBLASLT_TUNING": "@STRATA@/tools/hip/gfx1100-hipblaslt-100202.txt",
  "STRATA_DP_PREFILL": "1",      // data-parallel prefill: alternate chunks across both cards
  "STRATA_TP_PREFILL": "1",      // tensor-parallel prefill: both cards read every layer
  "STRATA_HIP_WMMA":   "1",      // RDNA3 WMMA matrix-core path
  "STRATA_SELECT_WMMA": "1",
  "STRATA_PEER_TRANSPORT": "host",  // cross-card traffic over mapped host memory (no NVLink needed)
  "GPU_MAX_HW_QUEUES": "8"       // keeps both cards busy; see the fork's RDNA3_SETTINGS.md
 }
}

All three switches matter: --tensor-parallel 2 plus STRATA_DP_PREFILL=1 and STRATA_TP_PREFILL=1. Turn either prefill path off and 128K prefill falls back toward the single-GPU 3,148 tok/s.

Launch:

cd ~/AI/strata-rdna3-test/fork
D="$HOME/AI/strata-rdna3-test/data"
.venv/bin/python rdna3/run.py swift-iq3-2gpu --data "$D" --gpus 0,1

The engine takes about 48 seconds to load and then serves an OpenAI-compatible API at http://127.0.0.1:18088/v1.

Verify both cards are actually working — this is where most first attempts fail:

# In a second terminal: both cards should show 23 GB+ VRAM and 250-300 W
watch -n 1 rocm-smi

# Smoke test
curl http://127.0.0.1:18088/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "swift-iq3", "messages": [{"role": "user", "content": "Write a parallel prime finder in Python"}], "temperature": 0.6, "max_tokens": 1024}'

nvtop showing both GPUs at 100% with 23.9 GB VRAM each

Figure 4 — a correctly deployed pair: 304 W / 303 W, 23.94 + 23.96 GB of VRAM resident, 100% utilization on both cards. If only one card moves, your --gpus or tensor-parallel switch is not taking effect.


Step 6 — Benchmark it and compare

A running server is not a verified deployment. Reproduce the protocol below, then compare:

Protocol (identical to our runs — a different protocol makes the numbers incomparable):

  • Per context size: 1 warm-up + 3 formal runs, median reported
  • temp=0, seed=42, 256 output tokens, prompt cache off
  • Ladder: 32K → 128K → 256K (261,632 tokens)
  • ./bench.sh also works if you just want a report for your own machine

Reference benchmark table: 32K, 128K, 256K

Figure 5 — reference numbers to compare against. Results within ±20% of these figures are normal.

Context Prefill Decode TTFT Needle test
32K 5,275.6 tok/s 133.7 tok/s 6.25 s —
128K 5,748.5 tok/s 133.7 tok/s 22.92 s —
256K (261,632 tok) 5,766.9 tok/s 119.3 tok/s 45.31 s 3/3 keys recalled
Stability — — — 0 OOM · 0 crashes (IQ3 & IQ4)

Decode speed by context length

Figure 6 — decode holds at 119 tok/s even at the full 256K-token context.

What to expect. Prefill is sensitive to CPU and memory platform: the fork’s author measures 6,700+ tok/s on a 9950X3D + DDR5 machine, while this rig (3700X + DDR4) lands at 5,748. Treat the speedup ratio (1.83x) as the portable number, not the absolute figure. And never quote a cold-start number: let the 48 s of loading and one warm-up run finish before you measure.

Switching to the high-precision pack: download IQ4 instead, repack in Step 4, and point the config at the new paths. At 128K, IQ4 prefill is actually slightly faster (5,881.3 tok/s, TTFT 22.40 s) but decode drops to 114 tok/s and host RAM peaks at 83 GB. Short version: IQ3 for speed, IQ4 for code and math accuracy.


Pitfalls (each one maps to a physical constraint — check here first when a deploy fails)

  1. PCIe topology is the number one killer. A second card in a chipset x4 slot cuts cross-card bandwidth to a quarter, and dual-GPU performance collapses toward single-GPU. Check with the lspci commands in Step 2; enable x8+x8 in BIOS
  2. --kv int8 is mandatory past 128K. Without it the KV cache balloons and you get an immediate OOM
  3. Too little RAM and the kernel’s OOM killer reaps the server. Check free -h; below 64 GB, pre-mount NVMe swap as a safety net: sudo fallocate -l 64G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
  4. Zero VRAM headroom is normal. --expert-cache auto fills both cards to 99.8–99.9%; do not run a desktop browser on the inference box
  5. Cold-start numbers do not count. Let the 48 s load and one warm-up run finish before measuring
  6. IQ4 costs 9 GB more RAM than IQ3. 83.16 GB vs 73.91 GB
  7. max-context must be large enough. Set ≥ 262144 before attempting 256K, or the 261,632-token prompt simply will not fit
  8. Do not skimp on cooling. Two cards at 303 W sustained will throttle in a bad airflow path, and your throughput will visibly sag

Bottom line

  • The pairing is real. TP=2 plus dual prefill: 83% faster prefill, TTFT cut by nearly 20 seconds. Honestly below 2.0x — cross-card AllReduce is a physical ceiling — but far beyond “two models running separately”
  • Old platforms hold up. No AVX-512 on the 3700X is fine; a ~98% expert-cache hit rate bypasses the memory-bandwidth bottleneck
  • Pin the commit. e1dad2dc. Cross-version comparison is meaningless
  • Make it a service once you are happy: a systemd unit with automatic restart and a generous start timeout is the production-ready setup (templates included in the build pack)

Questions, corrections, or a build that behaves differently? Drop a comment below or come find us on the GeekLab AI YouTube channel.


Sources: Issue #108 dual-GPU measurement report, Issue #110 IQ4 follow-up report, final_report.json / iq4_report.json benchmark data, suite.log run logs. All figures are from real hardware runs; reproduce them with the protocol in Step 6.

About The Author

Leave a Reply

Your email address will not be published. Required fields are marked *