Ryzen AI Max+ 395 results: 16.68 tok/s with UD-Q5_K_XL, Vulkan and MTP 4

#41
by erstmalreden - opened

I tested Qwen3.8-27B as a local coding/general-purpose agent on a GMKtec EVO-X2 with Ryzen AI Max+ 395, Radeon 8060S and 128 GB unified memory under Windows 11.

Full reproducibility report, server flags and all measurements:
https://github.com/erstmalreden/qwen3.8-27b-ryzen-ai-max-395-benchmarks

Best stable setup

  • Quant: Unsloth UD-Q5_K_XL (18.83 GiB) plus BF16 mmproj (0.87 GiB)
  • Runtime: llama.cpp b10436 (6fed9f6ff)
  • Backend: Vulkan, full GPU offload
  • Context: 131,072; native model context 262,144
  • KV cache: q8_0 / q8_0, one slot
  • Flash Attention enabled
  • Embedded MTP predictor, 4 draft tokens, p_min=0.75
  • Model parameters from GGUF tensor shapes: 27,320,697,856

Reproducible 512-token reasoning benchmark

Variant Context Generation Prompt TTFT Process working set
UD-Q5_K_XL, MTP 4 64K 16.68 tok/s 33.87 tok/s 2.85 s 41.31 GiB
Q6_K, MTP 4 64K 14.24 tok/s 28.93 tok/s 3.33 s 46.10 GiB
Q8_0, MTP 4 64K 12.74 tok/s 31.44 tok/s 3.06 s 56.96 GiB
UD-Q5_K_XL, MTP 4 128K 16.45 tok/s 31.44 tok/s 3.06 s 44.16 GiB

MTP sweep at Q5/64K:

  • MTP 2: 15.54 tok/s, 87.77% draft acceptance
  • MTP 3: 15.77 tok/s, 80.13% acceptance
  • MTP 4: 16.68 tok/s, 83.80% acceptance
  • MTP 5: 15.28 tok/s, 82.07% acceptance

Four draft tokens were the fastest stable value. Moving from 64K to 128K cost only about 1.4% generation speed and 2.85 GiB additional working set.

Vulkan vs ROCm on this Windows system

  • Direct llama.cpp b10436 Vulkan: 16.68 tok/s
  • LM Studio 0.4.21, ROCm runtime 2.28.2, identical API test: 12.04 tok/s

Direct Vulkan was about 37% faster in this comparison. The official direct llama.cpp ROCm b10436 binary did not enumerate the gfx1151 device, although LM Studio's ROCm runtime worked. The installed AMD 26.7.1 WHQL driver was already current, so I did not replace drivers or force a system-wide ROCm change.

OpenCode agent observations

The GGUF-embedded Qwen3.8/Unsloth Jinja template worked with separated reasoning content, native XML tool calls, parallel tool calls, nested object arguments, tool-result continuation and vision markers.

Captured OpenCode request parameters were reasoning_effort=high (mapped by the template to xhigh), temperature=1.0, top_p=0.95, top_k=20, min_p=0, presence_penalty=0, max_tokens=32000, and tool_choice=auto. The tested main request exposed 41 tools.

The main practical bottleneck was cold prompt processing. A cold request with roughly 13,264 prompt tokens and all 41 tool schemas took about 154.5 seconds of prompt evaluation (85.83 tok/s in the server log); the full simple interaction, including a title request, took around 189 seconds. With KV/LCP reuse, new prompt portions repeatedly processed above 200 tok/s. One agent step averaged 23.04 generation tok/s, with short windows around 24-26 tok/s.

Those short agent-step peaks should not be confused with the sustained benchmark: the honest sustained result remains 16.45-16.68 tok/s, below a 20 tok/s target.

Functional tests

  • Multi-file coding task: diagnosed four failing tests, added validation, modified two production files, then passed 4/4 tests without editing tests
  • Parallel tool calls and nested JSON arguments
  • Recovery after an intentionally failed tool call
  • Web search/fetch against an official source
  • Playwright MCP navigation, computed DOM styles and screenshot capture
  • Vision correctly diagnosed text made invisible by identical foreground/background colors
  • Long agent loop without repetition loops or obvious token artifacts

I would especially appreciate comparisons or ideas about:

  1. Direct ROCm device detection for gfx1151 on Windows
  2. Newer llama.cpp Vulkan/MTP improvements
  3. Better p_min values for MTP 4
  4. Reducing the cold OpenCode tool-schema cost
  5. Other dynamic Q5 GGUFs on the same hardware
  6. Real near-128K prompt tests, not only a 128K configured context

All results are from one machine and one Windows software stack, so please treat them as reproducible observations rather than universal hardware claims.


Deutsche Zusammenfassung

Ich habe Qwen3.8-27B als lokalen Coding- und Allzweck-Agenten auf einem GMKtec EVO-X2 mit Ryzen AI Max+ 395, Radeon 8060S und 128 GB Unified Memory unter Windows 11 getestet.

Der vollständige zweisprachige Bericht mit allen Startparametern und Messwerten liegt hier:
https://github.com/erstmalreden/qwen3.8-27b-ryzen-ai-max-395-benchmarks

Bestes stabiles Setup

  • Unsloth UD-Q5_K_XL, 18,83 GiB, plus BF16-mmproj mit 0,87 GiB
  • llama.cpp b10436 (6fed9f6ff)
  • Vulkan mit vollständigem GPU-Offload
  • 131.072 Kontexttokens; das Modell unterstützt nativ 262.144
  • K/V-Cache q8_0/q8_0, ein Slot, Flash Attention
  • eingebauter MTP-Predictor mit vier Draft-Tokens und p_min=0.75
  • 27.320.697.856 Parameter laut GGUF-Tensorformen

Reproduzierbarer 512-Token-Reasoning-Benchmark

Variante Kontext Generation Prompt TTFT Working Set
UD-Q5_K_XL, MTP 4 64K 16,68 tok/s 33,87 tok/s 2,85 s 41,31 GiB
Q6_K, MTP 4 64K 14,24 tok/s 28,93 tok/s 3,33 s 46,10 GiB
Q8_0, MTP 4 64K 12,74 tok/s 31,44 tok/s 3,06 s 56,96 GiB
UD-Q5_K_XL, MTP 4 128K 16,45 tok/s 31,44 tok/s 3,06 s 44,16 GiB

Beim MTP-Vergleich mit Q5/64K waren vier Draft-Tokens der schnellste stabile Wert: MTP 2 erreichte 15,54 tok/s, MTP 3 15,77 tok/s, MTP 4 16,68 tok/s und MTP 5 15,28 tok/s. Der Wechsel von 64K auf 128K kostete nur etwa 1,4 Prozent Generationstempo und 2,85 GiB zusätzliches Working Set.

Vulkan gegen ROCm

  • Direktes llama.cpp b10436 mit Vulkan: 16,68 tok/s
  • LM Studio 0.4.21 mit ROCm-Runtime 2.28.2 im identischen API-Test: 12,04 tok/s

Vulkan war in diesem Vergleich rund 37 Prozent schneller. Das offizielle direkte llama.cpp-ROCm-Binary erkannte das gfx1151-Gerät nicht, während LM Studios ROCm-Runtime funktionierte. Der installierte AMD-Treiber 26.7.1 WHQL war bereits aktuell; Treiber oder systemweites ROCm wurden daher nicht erzwungen verändert.

OpenCode-Praxis

Das eingebettete Qwen3.8/Unsloth-Jinja-Template funktionierte mit getrenntem Reasoning, nativem XML-Tool-Calling, parallelen Tool Calls, verschachtelten Objektargumenten, Fortsetzung nach Tool-Ergebnissen und Vision-Markern.

Ein lokaler Capture-Endpunkt bestätigte diese OpenCode-Parameter: reasoning_effort=high (vom Template auf xhigh abgebildet), temperature=1.0, top_p=0.95, top_k=20, min_p=0, presence_penalty=0, max_tokens=32000 und tool_choice=auto. Der getestete Hauptrequest enthielt 41 Tools.

Der größte Praxisengpass war die kalte Promptverarbeitung. Ein Request mit ungefähr 13.264 Prompt-Tokens und allen Tool-Schemata benötigte rund 154,5 Sekunden Prompt-Auswertung beziehungsweise 85,83 tok/s im Serverlog. Mit zusätzlichem Titelrequest dauerte die einfache Gesamtinteraktion rund 189 Sekunden. Bei KV-/LCP-Reuse wurden neue Promptanteile wiederholt mit über 200 tok/s verarbeitet. Ein Agentenschritt erreichte durchschnittlich 23,04 Generationstok/s, kurze Messfenster etwa 24–26 tok/s.

Diese kurzen Agentenspitzen sind nicht mit dem Dauerbenchmark gleichzusetzen: Das ehrliche nachhaltige Ergebnis bleibt bei 16,45–16,68 tok/s und damit unter dem Ziel von 20 tok/s.

Bestanden wurden außerdem ein Mehrdatei-Codingtest mit abschließend 4/4 Tests, parallele Tool Calls, verschachtelte JSON-Argumente, Wiederaufnahme nach einem fehlgeschlagenen Tool, Websuche/WebFetch, Playwright-MCP-Navigation samt DOM-Stilen und Screenshot sowie ein Vision-Test. Lange Agentenschleifen zeigten keine Wiederholungsschleifen oder auffälligen Token-Artefakte.

Besonders hilfreich wären Vergleichswerte oder Ideen zur direkten ROCm-Geräteerkennung für gfx1151 unter Windows, neueren llama.cpp-Vulkan-/MTP-Verbesserungen, besseren p_min-Werten für MTP 4, der Reduktion des kalten OpenCode-Tool-Prompts und echten Prompts nahe 128K.

Alle Werte stammen von einem einzelnen Windows-System und sind als reproduzierbare Beobachtungen, nicht als allgemeingültige Hardwareaussagen zu verstehen.

What's the point of KV quantization on 128 GB memory? I tried it once and it was slightly slower that default values

Good point. I used q8_0/q8_0 as a conservative headroom setting while testing 128K context, MTP, the vision projector and OpenCode on unified memory. It was not intended as a speed optimization.
I did not run a controlled f16-versus-q8_0 KV-cache benchmark, so I should not imply that q8_0 was optimal. With 128 GB, one slot and a measured 44.16 GiB working set, f16 should still fit comfortably and may indeed be slightly faster.
Thanks for pointing this out — an identical f16/q8_0 A/B run would be the proper comparison.

Got it, if you run everything on single host, then it makes sense to save some RAM of course.

Exactly — the GPU, Windows, OpenCode and browser all share the same 128 GB, so q8_0 was mainly a conservative headroom choice. I may still benchmark f16 later for a clean comparison.

Uhm, how do I enable MTP here with llama-cpp?

I enabled it in direct llama.cpp, not on Hugging Face itself. With llama.cpp b10436, the MTP predictor is embedded in this GGUF, so no separate draft model is required.
Add these parameters to llama-server:
--parallel 1
--spec-type draft-mtp
--spec-draft-n-max 4
--spec-draft-p-min 0.75
--spec-draft-ngl all
Here, “MTP 4” means a maximum of four draft tokens. If your llama.cpp build does not recognize draft-mtp, update to a recent build. The full configuration is documented here:
https://github.com/erstmalreden/qwen3.8-27b-ryzen-ai-max-395-benchmarks#actual-server-parameters

Thanks, this indeed works nicely!

Sign up or log in to comment