Optimal llama.cpp + Qwen3.8-Flash-Next settings on Strix Halo

updated on: Sep 24, 2026  published:

Optimal configuration for running Qwen3.8-Flash-Next (176.94B MoE, qwen4exp arch) on a Strix Halo MiniPC with AMD Ryzen AI Max+ 395 (128 GiB LPDDR5x, Vulkan backend).

Requirements

ComponentDescription
HardwareFEVM FA-EX1 – Ryzen AI Max+ 395, Radeon 8060S (gfx1151), 128 GiB LPDDR5x-8500 (~215 GB/s bandwidth, ~112 GiB GTT on Linux)
llama.cppstrix-halo-llamacpp v0.7.5 (source dff60048, Vulkan, bundles Mesa 26.3.0-devel) – required
ModelQwen3.8-Flash-Next-UD-Q4_K_XL (~103.69 GiB, 4 shards, 176.94B params)
Model (smaller)Qwen3.8-Flash-Next-UD-IQ4_XS (~87.25 GiB, 3 shards) – fits more context, slightly lower quality
Model (MTP)mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf (~2.6 GiB) – shared MTP heads for speculative decoding
mmprojmmproj-BF16.gguf (~0.85 GiB, multimodal, optional)
Templatechat_template.jinja v21.3

Model architecture (qwen4exp): 48 blocks, hybrid SSM (Gated DeltaNet) + full attention every 4th layer, QSA sparse-attention indexer (top_k=2048, compress_ratio=4 → 12 QSA layers), PLE layer (16 n-gram heads), MoE 512 experts / 10 active per token, 262144-token context.

The “why special build”

qwen4exp routes attention through a QSA sparse-attention indexer. In stock llama.cpp, on every decode step the indexer re-pools the entire block-key cache — O(n_kv) work per token, in every QSA layer. As context grows this dominates decode and throughput collapses.

The fix (upstream issue ggml-org/llama.cpp#28012, in strix-halo-llamacpp v0.7.5) caches the pooled block keys per block and recomputes only the tail. Measured on this box (Q4_K_XL, depth 32k, no MTP):

Buildpp512 @ 32ktg32 @ 32k
stock pr28243215.6 t/s20.3 t/s
strix-halo-llamacpp v0.7.5321.8 t/s (+49%)23.6 t/s (+16%)

The prebuilt tarball bundles a matched Mesa 26.3.0-devel RADV driver and a _run wrapper that wires it up — no system driver changes needed.

Getting the build

Bash
# Prebuilt (recommended) -- self-contained, bundles the Vulkan driver
curl -LO https://github.com/Nathanw1014/strix-halo-llamacpp/releases/download/v0.7.5/strix-halo-llamacpp-vulkan-portable.tar.gz
tar xzf strix-halo-llamacpp-vulkan-portable.tar.gz
# -> vulkan/bin/{llama-server,llama-cli,llama-bench}, vulkan/driver/, vulkan/_run

The _run wrapper (or the env below) sets up the bundled driver and the perf flags:

Bash
HERE=/path/to/strix-halo-llamacpp/vulkan
export VK_ICD_FILENAMES="$HERE/driver/radeon_icd.x86_64.json"
export VK_DRIVER_FILES="$VK_ICD_FILENAMES"
export LD_LIBRARY_PATH="$HERE/driver:$HERE/bin"
export GGML_VK_MMID_ROWLISTS=1 GGML_VK_MMID_SMALLN=1 GGML_VK_MMID_BM64=1
export GGML_VK_MMID_WAVE32=1 GGML_VK_MMID_F16B=1 GGML_VK_MMID_M128=1
export GGML_VK_FA_WAVE32=0

Basic Launch (Vulkan)

Bash
#!/usr/bin/env bash
HERE=/path/to/strix-halo-llamacpp/vulkan
MODEL=/path/to/Qwen3.8-Flash-Next-UD-Q4_K_XL-00001-of-00004.gguf   # all 4 shards auto-loaded
TEMPLATE=/path/to/chat_template.jinja

# (driver env from "Getting the build" above, or just call $HERE/_run)

$HERE/bin/llama-server \
    --host 0.0.0.0 \
    --port 1234 \
    -c 0 \
    --n-gpu-layers 999 \
    --batch-size 2048 \
    --ubatch-size 1024 \
    --flash-attn on \
    --temp 1.0 \
    --top-p 0.95 \
    --top-k 20 \
    --min-p 0.0 \
    --prio 2 \
    --cpu-strict 1 \
    --threads 16 \
    --threads-batch 32 \
    --no-warmup \
    --jinja \
    --chat-template-file ${TEMPLATE} \
    -ctk q8_0 \
    -ctv q8_0 \
    --parallel 1 \
    --metrics \
    --alias "qwen3.8-flash-next-q4_k_xl" \
    -m ${MODEL}

Parameters and Rationale

ParameterValueWhy
-c (context)0Unbounded (model supports 262144). KV grows as needed; -ctk/-ctv q8_0 keeps it small
--n-gpu-layers999Offload everything to the iGPU (UMA: “GPU memory” is system RAM)
--batch-size2048Prompt-processing batch; bandwidth-bound, 2048 is fine
--ubatch-size1024Micro-batch size. Tested 1024 vs 2048 – no difference (bandwidth-bound MoE). 1024 keeps peak RAM lower
--flash-attnonFA on the bundled Mesa 26.3 is fast and stable for this model
--temp / --top-p / --top-k1.0 / 0.95 / 20This is a reasoning model (thinking mode via the template); looser sampling is appropriate
--min-p0.0Disabled – not needed when top-p/top-k are set
--prio 2 --cpu-strict 1–Elevated OS priority + strict thread pinning (PLE layer runs on CPU). --prio needs permission to set nice; harmless warning if denied
--threads / --threads-batch16 / 32CPU threads for the PLE layer and batch work; matches the 16-CPU Strix Halo
-ctk q8_0 -ctv q8_0q8_0Compresses the KV cache. Required – default (f16) drops prefill to ~70 t/s at depth. q4_0 gives no speed win and lower quality
--parallel1Required. The QSA pool cache is single-slot; >1 desyncs the indexer (upstream bug). One slot per server
--no-warmup–Skip the warmup pass (saves load time)

Multi-model / on-demand: run a router instead of one fixed model: llama-server --models-preset presets.ini --models-max 2 --host 0.0.0.0 --port 1234 and put the flags above under a [qwen3.8-flash-next-q4_k_xl] section in presets.ini. Models load on demand.

Multimodal Support (mmproj)

Bash
MM=/path/to/mmproj-BF16.gguf
# add to the launch command:
    --mmproj ${MM} \

Advanced Launch (MTP Speculative Decoding)

MTP uses a separate shared-heads draft (mtp-...-shared-Q8_0.gguf) to predict multiple tokens per step. On this box it delivers +33% decode (25.4 → 33.9 tok/s at ~4k depth) over no-MTP.

Add to the Basic Launch command:

Bash
MTP=/path/to/mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf

    --spec-type draft-mtp \
    --spec-draft-model ${MTP} \
    --spec-draft-n-max 3 \

MTP Parameters

ParameterValueWhy
--spec-typedraft-mtpMTP speculative decoding
--spec-draft-modelshared Q8_0The shared MTP heads file (loaded as the drafter)
--spec-draft-n-max3Up to 3 draft tokens/step. Tested 3 vs 5 – 5 is within noise (33.9 vs 34.7 tok/s) but adds checkpoint-restore overhead. 3 is the safe default

v0.7.5 MTP uses context checkpoints (≈112 MB × 48 layers per rejected round). It’s a net win here, but if you ever see it go negative, drop --spec-draft-n-max to 1 or disable MTP.

Performance

Measured (strix-halo-llamacpp v0.7.5, bundled Mesa 26.3)

Depth 32768, Q4_K_XL, llama-bench (no MTP):

MetricValue
Prompt processing (pp512 @ 32k)~320 tok/s
Decode (tg32 @ 32k, no MTP)~23.5 tok/s
Decode (MTP n-max=3)~30–34 tok/s (depth-dependent)

vs stock pr28243 (same flags): 15–17 tok/s decode, ~216–300 tok/s PP.

HIP / ROCm Backend (alternative)

The Vulkan build above is the safest choice, but a HIP/ROCm build is a strong alternative on this box. pwilkin/llama.cpp @ strix-halo (b0f31f58, 2026-09-16) is compiled against stock ROCm 10 with a custom retained-PM4 ROCr/HIP pair (pwilkin/rocm-systems @ ilintar-experiments) injected at runtime via LD_LIBRARY_PATH. It carries both the QSA pool-cache fix and the GPU TOP_K fix, and measures ~1.7× faster on prefill at decode parity (no MTP).

A/B (Q4_K_XL, depth 32k, identical flags)

testHIP (retained-PM4)Vulkan (v0.7.5)ratio
pp512 @ 32k~540 t/s326.97 t/s~1.7×
tg8 @ 32k (no MTP)22.07 t/s22.46 t/s0.98×

With MTP (--spec-type draft-mtp, shared Q8_0 head) decode reaches ~43 tok/s (measured, ≤2k ctx) — vs ~34 tok/s for the Vulkan build at 4k depth; at 8k with real coding workloads the community reports ~47 tok/s (#27950). The GPU TOP_K fix (hipCUB / radix, #26592 / #27466) keeps the QSA indexer’s ggml_top_k on-GPU past ne=1024, where stock HIP falls back to CPU and decode collapses (the knee is at d1024).

Differences vs the Vulkan build

aspectVulkan (v0.7.5)HIP (strix-halo)
KV cache typeq8_0 (fast, small)f16 required — q8_0 hits a GGML_ASSERT in qwen4exp
depth-collapse fixQSA pool-cache #28012QSA pool-cache + GPU TOP_K (hipCUB/radix)
prefill @ 32k~327 t/s~540 t/s
runtimebundled Mesa 26.3 RADVretained-PM4 ROCr/HIP via LD_LIBRARY_PATH

Building it (Docker, gfx1151)

A self-contained stack (Dockerfile + docker-compose.yaml + build.sh + fetch-sources.sh + .env) compiles the three components — ROCr → HIP (clr) → llama.cpp — for gfx1151, then serves/benches it with ROCm GPU passthrough. The key idea: llama.cpp compiles against stock /opt/rocm; the retained-PM4 ROCr/HIP pair is built separately and injected at runtime via LD_LIBRARY_PATH.

Dockerfile

Dockerfile
ARG BASE_IMAGE=rocm/dev-ubuntu-24.04:10.0.0-full
FROM ${BASE_IMAGE}
# build deps — note the non-obvious ones: xxd (ROCk HSACO->ASCII),
# libgl-dev (clr OpenGL), libelf-dev (ROCk), CppHeaderParser (clr hipamd)
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential cmake ninja-build git pkg-config ccache python3 python3-pip \
        xxd perl libdrm-dev libnuma-dev libelf-dev libdwarf-dev \
        libgl-dev libegl-dev libglu1-mesa-dev libopenmpi-dev libssl-dev \
      && rm -rf /var/lib/apt/lists/*
RUN pip3 install --break-system-packages --no-cache-dir CppHeaderParser
WORKDIR /work
COPY fetch-sources.sh build.sh ./
RUN ./fetch-sources.sh   # clone the two repos at pinned commits (see .env)
RUN ./build.sh           # ~1h: ROCr -> HIP(clr) -> llama.cpp (GGML_HIP, gfx1151)
# custom ROCk/HIP (retained-PM4) FIRST so they shadow stock /opt/rocm at load
ENV LD_LIBRARY_PATH=/work/runtime/hip/lib:/work/runtime/rocr/lib:/opt/rocm/lib:/opt/rocm/lib64:/opt/rocm/lib/llvm/lib:/work/build/llama.cpp/bin \
    HSA_OVERRIDE_GFX_VERSION=11.5.1 ENABLE_RETAINED_PM4=1 HSA_ENABLE_SDMA=0
ENV PATH=/work/build/llama.cpp/bin:${PATH}

build.sh (the three components)

Bash
# 1/3 ROCk (retained-PM4 HSA runtime)
cmake -S src/rocm-systems/projects/rocr-runtime -B build/rocr -G Ninja \
  -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=$RUNTIME/rocr
cmake --build build/rocr -j$(nproc) && cmake --install build/rocr

# 2/3 HIP/clr (retained-PM4). HIP_COMMON_DIR must be the HIP *source* tree
# (has include/hip + cmake + *.cmake.in); stock /opt/rocm lacks the .in templates.
HIP_COMMON_DIR=$SRC/rocm-systems/projects/hip
cmake -S src/rocm-systems/projects/clr -B build/hip -G Ninja \
  -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCLR_BUILD_HIP=ON -DCLR_BUILD_OCL=OFF \
  -DROCM_PATH=$RUNTIME/rocr -DCMAKE_PREFIX_PATH=$RUNTIME/rocr;/opt/rocm \
  -DHIP_COMMON_DIR=$HIP_COMMON_DIR -DHIP_PLATFORM=amd \
  -DLLVM_BIN=/opt/rocm/lib/llvm/bin -DClang_BIN=/opt/rocm/lib/llvm/bin \
  -DCMAKE_INSTALL_PREFIX=$RUNTIME/hip
cmake --build build/hip -j$(nproc) && cmake --install build/hip

# 3/3 llama.cpp (GGML_HIP, gfx1151) — against stock /opt/rocm
cmake -S src/llama.cpp -B build/llama.cpp -G Ninja \
  -DCMAKE_BUILD_TYPE=Release -DGGML_HIP=ON -DGGML_HIP_NO_VMM=ON -DGGML_HIP_GRAPHS=ON \
  -DGGML_HIP_MMQ_MFMA=ON -DGGML_CUDA_FA=ON -DGGML_NATIVE=ON -DGGML_OPENMP=ON \
  -DGPU_TARGETS=gfx1151 -DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++
cmake --build build/llama.cpp -j$(nproc)

docker-compose.yaml (ROCm GPU passthrough + server)

YAML
x-rocm-gpu: &rocm-gpu
  devices: ["/dev/kfd", "/dev/dri"]          # ROCm = raw KFD + DRM nodes
  security_opt: ["seccomp:unconfined"]
  environment:
    - HSA_OVERRIDE_GFX_VERSION=11.5.1
    - ENABLE_RETAINED_PM4=1
    - HSA_ENABLE_SDMA=0
  volumes: ["/mnt/local/models:/mnt/local/models:ro"]

services:
  server:
    build: .
    image: strix-pwilkin:gfx1151
    <<: *rocm-gpu
    ports: ["${SERVER_PORT:-1234}:1234"]
    command: >
      llama-server
      -m $MODEL -md $MTP_DRAFT --mmproj $MM_PROJ
      --spec-type draft-mtp --spec-draft-n-max 3
      -ngl 999 -fa on -ctk f16 -ctv f16
      -t 16 -tb 32 -b 2048 -ub 1024
      -c ${CTX:-262144}
      --cache-ram 24576 --cache-reuse 1024
      --host 0.0.0.0 --port 1234 --jinja
    restart: unless-stopped
  bench:
    image: strix-pwilkin:gfx1151
    <<: *rocm-gpu
    command: >
      llama-bench -m $MODEL -ngl 999 -fa on -p 512 -n 8 -d 32768
      -b 2048 -ub 1024 -ctk f16 -ctv f16 -t 16 -r 3
    profiles: ["bench"]

.env (pinned commits + model + ctx)

Bash
LLAMA_GIT_SHA=b0f31f5876ef3856b55f5bb88072cc96e5effafe        # pwilkin/llama.cpp@strix-halo
ROCM_SYSTEMS_GIT_SHA=7dda3ac6cfe6bbe0b7f08c23a67cfa118d8641a1 # pwilkin/rocm-systems@ilintar-experiments
GPU_TARGETS=gfx1151
CTX=262144
SERVER_PORT=1234
MM_PROJ=/mnt/local/models/.../Qwen3.8-Flash-Next-GGUF/mmproj-BF16.gguf   # vision projector

Run it

Bash
cd strix-pwilkin/
docker compose build          # ~1h; bakes /work/build/llama.cpp/bin + /work/runtime/{rocr,hip}
docker compose up -d server   # serve: ctx 262144, MTP on, f16 KV, prompt cache, port 1234
docker compose run --rm bench # plain-decode A/B (llama-bench can't see draft flags)

Launch flags are the Basic Launch set, except use -ctk f16 -ctv f16 (not q8_0). --cache-ram 24576 --cache-reuse 1024 enable the in-process prompt cache with KV shifting; note f16 KV holds ~half the tokens of q8_0 in the same RAM budget, so raise --cache-ram if prefix reuse is critical. --mmproj enables vision, but llama.cpp disables cache_reuse when a multimodal model is loaded (KV shifting is incompatible with image tokens) — so with --mmproj the prompt cache still works for repeated prefixes, but KV-shifting reuse is off.

For Other Tasks

The template enables thinking mode. Give it enough max_tokens to finish reasoning before the final answer.

Agentic / coding (deterministic)

Bash
--temp 0.3 --top-p 0.5 --top-k 5

Creative text

Bash
--temp 1.0 --top-p 0.95 --top-k 40

Known Issues

  • Stock llama.cpp is unusable at depth – the QSA indexer re-pools the block-key cache O(n_kv)/token. Use strix-halo-llamacpp v0.7.5+ (or a build with the QSA pool-cache fix). This is the #1 gotcha.
  • --parallel 1 is mandatory – the QSA pool cache is single-slot; multiple slots desync the indexer. Run one server per model (or a router with one slot each).
  • KV cache type – default (f16) drops prefill to ~70 tok/s at growth. Always set -ctk q8_0 -ctv q8_0.
  • Chat template is required – use chat_template.jinja v21.3; the default template can break tool calls / loops.
  • Slot-save files are version-locked – v0.7.5’s indexer V-cache is 1-element wide; slot-save files from other builds won’t restore. In-process prompt cache is unaffected.
  • Bundled driver – the build ships Mesa 26.3.0-devel. Use the _run wrapper or set VK_ICD_FILENAMES/LD_LIBRARY_PATH (see “Getting the build”); the host driver (Mesa 26.1) is ~7% slower on prefill.
  • --prio 2 may print Permission denied if the process can’t set nice values – harmless, the server runs at default priority.
Llama.cpp Qwen3.8 Strix-Halo Vulkan Hip Rocm Moe Qsa Mtp Inference Amd