LLM Benchmark Suite on Metis (/data/sources/llm-bench) + Strix Halo BIOS memory
Last updated 05/11/2026 · migrated-from-outline, llm, metis
.
SUPERSEDED 2026-10-18/19: prod now runs llama-flashnext (Qwen3.8-Flash-Next Q2_0 + MTP, 43-50 t/s) — current state, flags and measurements in
llm-serving-metis. The “final picture” below is the 2026-10-12 Ornith-era snapshot; this doc stays valuable for the benchmark methodology, scripts and the BIOS/TTM memory notes.PICTURE 2026-10-12 (historical):
- Winner and prod config: Ornith-1.5-35B-A3B Q4_K_M,
-c 131072 -np 1 -b 1024 -ub 1024, KV q4_0, embedded chat template, thinking cap 4096, MTP self-draft**--spec-type draft-mtp --spec-draft-n-max 2**. Prodllamais up on :8000. Details and rollback: “Local LLM Serving on Metis (llama.cpp)”.- Why Ornith: eval 8/9 like the 27B, 2.4x faster wall-clock (283 s vs 673 s), 2.8x decode at 98k, 3x faster cold start. Full speed / quality / total rankings:
/data/tests/llm-bench/RESULTS.md.- Variant tests (run_variants.sh,
**RESULTS.md**section “Ornith variant tests”):
- Embedded template kept: the vendor template returns HTTP 500 on 3 of 13 edge cases (two system messages, system after user, no user message), same eval quality.
- Thinking budget 512/1024/2048/4096: quality flat within noise (6.0-6.7 of 9), time per task 13.5 to 36.5 s. 4096 stays as a server-side safety cap.
- MTP: plain ~76 t/s, n-max 3 helps at short context, n-max 2 is the best setting (90-94 t/s short, 102-104 on the prod coding prompt).
- n-max 2 context sweep on prod (cold decode t/s, plain in brackets): 8k 88.6 (73.8), 32k 83.6 (68.4), 64k 69.7 (61.5), 100k 59.5 (55.9), 120k 56.2 (51.9). Cold prefill 6-10 % slower, GTT 22.9 GiB (+1.6 GiB). Realistic expectation: 70-90 t/s in normal sessions, ~56 t/s at 120k. The old setup gave ~15 t/s in long sessions.
- Quality complaint check 2026-10-13 (replay A/B,
**RESULTS.md**section “Quality complaint check”): the user found Ornith answers in Hermes Desktop mostly wrong. The failing prompts (real Hermes sessions) were replayed against Q4_K_M, Q6_K and the 27B+DFlash, n=5 per mode. Correct on the two context-reading cases A+B, of 20: Q4_K_M 11, Q6_K 8, 27B 15; the pure-knowledge case C is 0/5 for every model. Higher quant does not help (Q6_K slower, no better; Q8_0 skipped), the 27B is best but 5-14x slower and Ornith’s result flips with think/nothink. Decision: Ornith Q4_K_M + MTP n-max 2 stays. Harness problems (cwd override, date-only prompt) were fixed separately, see the Hermes doc. Tools:replay_ab.py,replay_model.sh(port 8124),replay_all.sh; a full 3-model window keeps prod down ~50 min.
STATE 2026-10-12 (end of benchmark): Benchmark finished, winner Ornith-1.5-35B-A3B Q4_K_M — production
compose.ymlswitched to it (see “Local LLM Serving on Metis”). Rankings moved out of the suite README into/data/tests/llm-bench/RESULTS.md(speed / quality / total + verdicts). Xing/ROCmFPX removed entirely (scripts, fork build, host-runner glue inrun.sh;lib.shkeeps an unused host branch). Weights deleted (~137 GB): Qwen3.6-35B, Saluki, Swift, ISTA 27B (ranked below 4th), Flash-Next Coder, Xing (untested). Kept: Ornith, Gemma + MTP drafter, Flash-Next Q2_0, 27B cache,dflash/,mtp/. Model scripts for deleted rows remain (./run.sh <model> --download). Sections below that mention the deleted models/Xing as present are historical.
Speed-benchmark suite for candidate primary LLMs: **/data/sources/llm-bench** (relocated from the old /data/tests/llm-bench; path verified 2026-10-24; the historical path mentions below are stale). README.md there is the full procedure. One script per model, logs in logs/, ./compare.py for the table. Reviewed + fixed 2026-10-12.
Two measurement paths
./run.sh <model> --bench—llama-bench, plain model, no speculative decoding. Tests:pp512,pp16384,tg128(-p 512,16384 -n 128)../run.sh <model> --serve-bench—llama-serverwithSERVE_ARGS+server_probe.py(reads thetimingsblock: decode t/s, ~16K prefill t/s, draft acceptance). This is how the 27B + DFlash2 baseline is measured.run_all.sh=--benchfor all four models +--serve-benchfor the 27B (SERVER_BENCH=all|""to change).
Gotchas (all verified against the real binaries)
**llama-bench**rejects**-c**and every**--spec-\***flag (invalid parameter for argument) — aborts the whole run. Keep those inSERVE_ARGS, notBENCH_EXTRA.-pgonly reports the combined prefill+decode rate; use-p/-nlists for independent pp/tg numbers.-o jsonlrows haven_prompt,n_gen,avg_ts— nopp512keys (the oldcompare.pyregex matched nothing).- Port 8123 is Home Assistant (host networking) — test server uses 8130 (
LLM_SERVE_PORT). - Symlinks into
/data/docker/llama/modelsmust be relative (ln -sfr): the dir is/modelsinside containers, an absolute host path dangles. - Thinking-budget flag is
--reasoning-budget(envLLAMA_ARG_THINK_BUDGET), not--thinking-budget. - Don’t stack stop/restart of prod:
run_all.shsetsLLM_BENCH_PROD_HELD=1; prod is only restarted if the suite stopped it. (Prod containerllamamay not exist/run —docker compose -f /data/docker/llama/compose.yml up -d.) - HF downloads die with curl 92 (HTTP/2 CANCEL) — plain
--retrydoesn’t cover it; use--retry-all-errors. - Xing (ROCmFP4) runs only on the host ROCmFPX fork (
/data/tests/rocmfpx/build/bin, built 2026-10-11 @ cbc2cd5). Unverified:-fa 0+-ctv q4_0may abort at context creation (fallbackBENCH_FA=1).
Strix Halo / Framework Desktop BIOS memory (verified 2026-10-12)
- Wanted: iGPU Memory Configuration = Custom, iGPU Memory Size = 512 MB, save + exit, plus kernel
ttm.pages_limit=14680064 ttm.page_pool_size=14680064(56 GiB GTT; kernel 7.0 usesttm.*, notamdttm.*). Framework KB: “Changing Memory Allocation (AMD Ryzen AI Max 300 Series)”. - Verify:
sudo dmesg | grep -iE 'of (VRAM|GTT) memory'→512M of VRAM,57344M of GTT;bash /data/maintenance/checkram.sh→ MemTotal ≈ 61-62 GiB.free -hdoes NOT show GTT. - Wrong carve-out (48 GB seen): MemTotal ≈ 14.9 GiB; Vulkan lists a bogus 106496 MiB (VRAM+GTT summed); the HIP fork counts only free system RAM (~8.6 GiB) for UMA devices.
llama-bench --list-devices(container + host fork) is a quick check: both should show ~56 GiB.
First smoke numbers (not the real run)
27B server probe with DFlash2: ~336 t/s prefill @16K tokens (≈ 48 s cold start), decode 23–41 t/s, draft acceptance 36–54% on code, ~100% on repetitive text.
Candidate review (2026-10-12)
- README now has “Expected results” (predictions before run), quality evidence, context ceiling, decision rule (quality gate via
tools/eval.py-> time-to-solution -> headroom >=64k ctx). - Missing strongest candidate:
ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-Coder-GGUF(IQ1_M dir only; expert-pruned 256/512, 6B active; shard1 ~29.6 GB resident + 28.8 GB n-gram mmap; vendor SWE-bench Verified 75.6, LCB v6 86.3). ~12 GB less resident than Q2_0. Not yet added (asked user). - Optional extras: Flash-Next IQ3_XXS (47 GB resident, may fit now with 56 GiB GTT), Nemotron-3.5-Lightning-30B-A3B (ggml-org Q4_0, agentic quality unknown).
- Xing risks: needs ROCmFPX fork; KV ~0.4 MiB/token (x2 with MTP), KV quant ignored on arch -> ctx ceiling ~64-96k without MTP, ~32k with MTP; verbose/Chinese thinking. The “PPL 318,130 at -ub 512” note is about the imatrix build only (unquantized MUL_MAT_ID bug), not runtime.
- Skip: GLM-5.3-Flash, Gemma-4-26B-A4B, gpt-oss-120b, Devstral-Small-2, Mistral-Small-4-119B, ISTA 27B GSQ (user eval rejected), unvetted third-party fine-tunes.
Matrix change (2026-10-12, later)
- Added
models/qwen3.8-flash-next-coder-iq1m.sh(ISTA Coder, dirIQ1_M/, shard1 29.6 GB + shard2 28.8 GB, no mmproj;-c 65536). Dir name misleading: retained weights ~3.5 bpw, so decode speed is NOT expected to beat Q2_0 — benefit is ~8 GB less resident memory. run_all.shnow takesMODELS="..."(default: 27B, 35B-A3B, Flash-Next Q2_0, Coder). Xing is opt-in (MODELS="xing4.0-29b-a4b-rocmfp4" ./run_all.sh): KV-heavy ctx ceiling, verbose thinking, fork-only. Files/fork build kept (download complete 16.6 GB).- Suite still NOT run (user instruction).
Depth pass + revised decision rule (2026-10-12)
- User reports ~15 t/s in long conversations on prod (27B + DFlash2; ~30 t/s short) and is willing to trade some quality for a big speed gain. So
tg128(empty ctx) is not the yardstick. lib.sh:run_benchnow runs a secondllama-benchpass-p 0 -n 128 -d 16384,32768(1 rep;BENCH_DEPTHS,BENCH_DEPTH_REPS) -> rowstg128@d16384/@d32768(compare.py already labels depth).llama-bench -d/--n-depthexists in the prod image (build 11541). Smoke-tested on 27B (tiny depths): fine. Suite ~40 min.- Quality gate relaxed to a floor (~6-7/9, no token inflation); 35B-A3B is a live candidate again -> keep it in the default matrix. “Big gain” ~ >=2x the 27B’s long-session rate.
run_all.shwriteslogs/run_all.status(state, step N of M, current, finished steps + durations).- Use
tools/bench-depth.py --url http://127.0.0.1:8130+tools/eval.py <label> --url ...on finalists (README step 5).
RESULTS of first full run (2026-10-12 08:57-09:18, 21 min, all 5 steps ok)
llama-bench, no spec decoding (t/s):
| model | pp512 | pp16384 | tg128 | tg@d16k | tg@d32k |
|---|---|---|---|---|---|
| 27B Q4_K_XL | 434.9 | 345.0 | 12.4 | 12.0 | 11.7 |
| 35B-A3B Q4_K_M | 1567.7 | 1235.5 | 63.5 | 60.5 | 57.4 |
| Flash-Next Q2_0 | 343.1 | 435.2 | 29.9 | 28.0 | 27.6 |
| Flash-Next Coder IQ1_M | 405.5 | 443.3 | 26.4 | 25.1 | 24.5 |
| Server probe 27B + DFlash2: prefill 337.7 t/s @16k, decode 26.9 t/s, accept 44%. |
- Depth barely slows llama-bench decode (-6..-9% at 32k) -> user’s prod ~15 t/s in long sessions is NOT attention cost; suspect DFlash2 acceptance at depth / thinking. Still to measure: 27B+DFlash at depth (bench-depth.py).
- 35B-A3B ~2.1-2.4x the 27B+DFlash probe; Flash-Next Q2_0 ~= 27B+DFlash probe w/o spec decoding; Coder 12% slower than Q2_0 (no speed win, only ~8 GB less resident).
- Next: eval.py + bench-depth.py on 35B-A3B (speed winner) and 27B (reference). Production llama container still down after the run.
Quality + long-context pass (2026-10-12, ./run_quality.sh, ~76 min)
Setup: prod sampling (temp 1.0/top-p 0.95/top-k 20), thinking cap 4096, -c 131072, -np 1, KV q4_0, DFlash2 for 27B. Port 8130 (HA uses 8123). All three loaded at 128k; Flash-Next ~45 GiB RAM used.
| 27B+DFlash2 | 35B-A3B | Flash-Next Q2_0 | |
|---|---|---|---|
| eval.py | 8/9 | 6/9 | 8/9 |
| tokens (9 tasks) | 19.0k | 36.6k | 24.6k |
| wall (9 tasks) | 673 s | 587 s | 839 s |
| tool calling | 4/4 | 4/4 | 4/4 |
| retrieval 8k-98k | 5/5 | 5/5 | 5/5 |
| cached decode 8k/32k/64k/98k t/s | 28/26.6/18.8/20 | 61/57/52/48 | 29/28/27/26 |
| cold start 8k/32k/64k/98k | 23/104/260/492 s | 6/30/82/160 s | 19/83/204/362 s |
Takeaways:
- 27B+DFlash2: best quality + token efficiency, weak at long context (decode ~19-20 t/s past 64k, cold 98k ~8 min) - matches observed ~15 t/s in prod (256k + thinking).
- 35B-A3B: ~2.4x faster at depth, 3x faster cold start, but ~2x tokens on reasoning (hits 4096 thinking cap) -> only ~13% wall-clock win on eval, 6/9 vs 8/9. Tool-heavy turns (little thinking) likely show full 2x+ but NOT measured.
- Flash-Next Q2_0: side-grade, not worth switching (839 s vs 673 s, 45 GiB RAM).
- Caveats: 9 tasks x 1 sample (noisy); math_coprime_pairs fails for all models; retrieval probe too easy; 256k not measured.
- Gotchas: llama-bench rejects
-c/--spec-*(spec decoding only measurable via llama-server); Coder “IQ1_M” folder is actually ~3.5 bpw. - Production
llamacontainer was left DOWN after the suite; restart withdocker compose -f /data/docker/llama/compose.yml up -d(only on user’s OK). - Possible follow-ups: 35B with lower thinking budget; tool-heavy turn bench; 256k test; MTP for Flash-Next; run 27B + 35B side by side (unverified fit).
Candidate re-check (2026-10-12): web + HF research for Strix Halo 64 GB
Engine: local kyuz0/amd-strix-halo-toolboxes:vulkan-radv = llama.cpp build 11541 (commit f2918cabb) — supports --spec-type draft-mtp (needs ≥ b11259 for multi-turn MTP, PR #29638). No newer image needed.
Shortlist (file sizes verified via HF tree API)
| candidate | file | size | why / risk |
|---|---|---|---|
Ornith-1.5-35B-A3B (ornith-ai/Ornith-1.5-35B-A3B-GGUF, MIT) |
Ornith-1.5-35B-Q4_K_M.gguf |
21.71 GB | Same qwen3_5_moe arch/size as Qwen3.6-35B-A3B => ~60 t/s expected. Agentic-RL fine-tune. slb350 board: combined 226/285 vs 205 for Qwen3.6-35B-A3B. Risk: very verbose thinking (4-12 min answers), vendor evals used a modified chat template, Terminal-Bench 67.8 vs 52.5 is self-reported. MTP variant: mudler/Ornith-1.5-35B-A3B-APEX-MTP-GGUF (17.4 / 23.7 GB) |
Gemma-4-26B-A4B (unsloth/gemma-4-26B-A4B-it-GGUF) |
UD-Q4_K_XL + mtp-gemma-4-26B-A4B-it.gguf drafter |
17.0 + 0.46 GB | Speed pick: 52.9 t/s plain, 83 t/s QAT+MTP n=2 (slb350). Weak agentic: Polyglot 22/65, fell for prompt injection at Q8, thrashes in cumulative agent runs |
Underdog-Saluki-27B IQ2-mix-MTP (Kujira/Underdog-Saluki-27B-1.0-MTP-GGUF) |
...IQ2-mix-MTP.gguf |
8.35 GB | 2-bit Qwen3.8-27B; est. 40-55 t/s (UNMEASURED). ~1 in 5 parallel tool-call replies have formatting slips (bad for Hermes); weaker math (AIME25 79 vs 97). Self-run numbers |
Swift-1.5-Qwen3.8-27B-GSQ-RCO (ukisai/...-GGUF) |
IQ3_XXS-mtp |
10.44 GB | Post-trained for 16-24% fewer thinking tokens. Non-Apache license (commercial limits >$1M revenue), only KLD no task scores, card speedup claims contradict themselves |
| ISTA-DASLab/Qwen3.8-27B-GSQ-RCO-GGUF | IQ3_S-mtp |
12.1 GB | Control for Swift |
Gemma-4-31B QAT Q4_0 (google/gemma-4-31B-it-qat-q4_0-gguf) |
17.65 GB | ~25 t/s w/ MTP n=4; marginal vs current 27B |
Dropped (with reason)
Ternary-Bonsai-2-27B (needs PrismML fork; PQ2_0/PTQ1_0 slow on Vulkan, garbled on HIP gfx1151) · bytkim/Qwen3.8-27B-pi (Pi-harness tuned, no numbers) · empero-ai Qwen3.8-35B-A3B-Distill (Qwen3.6 SFT, no agentic evidence; no official Qwen3.8 35B-A3B exists) · Ornith-1.5-9B (weak on long tasks) · GLM-5.3-Flash (320B, no stock support) · Kolibri-1 (needs patch) · Qwen3-Coder-Next (41 GiB, 40 t/s, no advantage) · gpt-oss-120b (59 GiB, doesn’t fit) · Nemotron-3-Nano (weak) · Mellum2.1 (sub-agent at best) · Flash-Next Coder (already tested, dropped).
Engine / backend findings
- Gufo runtime (
ghcr.io/gufo-org/toolboxes/gufo-runtime): ~2x llama.cpp prefill on 27B (pp 387 vs 194 @65k) but same long-ctx decode; daily releases, open prompt-cache re-prefill bugs, one amdgpu crash report, no independent 64 GB data. Not recommended now. Vendor bench (128 GB box): 27B Q4 AR decode 12 t/s @d0, 8.5 @131k; DFlash2 26 -> 14.7 t/s — matches our observed ~15 t/s in production. - Vulkan tuning (strixhaloguide):
-b 2048 -ub 512(ub > b is silently clamped), Mesa kisak 26.1.7 vs 25.2.8 = +17% pp512,--no-mmap,-fa 1. - HIP: llama.cpp commit
c7d87229corrupts output on gfx1151 (issue #25992, closed by stale bot, not fixed). Avoid unpatched HIP; kyuz0rocm-10.0carries a patch. - Vulkan(RADV) wins decode, ROCm wins prefill on MoE.
- MTP on dense 27B ~1.84x at n=3; only ~1.2x on 35B-A3B MoE (slb350).
- Caveat: eval.py has 9 tasks x 1 sample; 2-task gap = hint, not proof.
Round 2 results (2026-10-12, 128k ctx, thinking cap 4096, KV q4_0)
| tg128 | tg128 @32k | eval.py | tokens | wall | tools | decode @8k->98k | cold @98k | |
|---|---|---|---|---|---|---|---|---|
| Ornith-1.5-35B-A3B Q4_K_M | 76.8 | 69.7 | 8/9 | 21.3k | 283 s | 4/4 | 74->57 | 164 s |
| Gemma-4-26B-A4B + MTP | 51.9 | 44.2 | 8/9 | 36.9k | 447 s | 3/4 | 79->49 | 208 s |
| Qwen3.6-35B-A3B | 63.5 | 57.4 | 6/9 | 36.6k | 587 s | 4/4 | 61->48 | 160 s |
| 27B Q4_K_XL + DFlash2 (prod) | 12.4 | 11.7 | 8/9 | 19.0k | 673 s | 4/4 | 28->20 | 492 s |
| Flash-Next Q2_0 | 29.9 | 27.6 | 8/9 | 24.6k | 839 s | 4/4 | 29->26 | 362 s |
| Saluki 27B IQ2-mix + MTP | 22.4 | 20.2 | 7/9 | 26.4k | 874 s | 4/4 | 37->25 | 566 s* |
| Swift 27B IQ3_XXS + MTP | 18.8 | 17.2 | 7/9 | 20.3k | 681 s | 4/4 | 37->21 | 568 s* |
| ISTA 27B IQ3_XXS + MTP (control) | 18.8 | 17.2 | 6/9 | 22.4k | 766 s | 4/4 | 33->20 | 568 s* |
* -ub 512 (see below). Retrieval 10/10 everywhere. Ornith/Gemma/27B/Flash-Next fail only math_coprime_pairs (everyone does).
Verdict: Ornith-1.5-35B-A3B Q4_K_M replaces the 27B+DFlash2 as primary: same eval result and token economy, 2.4x faster wall-clock, 2.8x decode @98k, 3x cold start, cached agent turn 6-9 s vs 17-25 s. Recommended flags: -ctk q4_0 -ctv q4_0 -b 1024 -ub 1024 -c 131072 -np 1, --temp 0.6 --top-p 0.95 --top-k 20 --min-p 0.0, LLAMA_ARG_THINK_BUDGET=4096, no spec decoding. Keep the 27B as fallback for hard math/reasoning.
Gotchas:
-ub 2048crashes the IQ2/IQ3 27B quants at ~64k prefill withvk::DeviceLostError(also with MTP off and checkpoints off);-ub 512is stable. Debug by running the server by hand anddocker logs(the suite deletes the container).- Per-model sampling needs the
QUALITY_POSThook inrun.sh(QUALITY_COMMON comes last on the command line and would override per-model settings). - Gemma MTP uses a separate drafter file (
--spec-draft-model,mtp-gemma-4-26B-A4B-it.gguf); the Qwen3.8 27B GSQ/Saluki GGUFs embed the MTP head (--spec-type draft-mtponly). - MTP on the 27B-class quants (n=3) was not better than DFlash2 at depth (20-25 vs 20 t/s @98k).
Not verified: Ornith’s embedded chat template vs the vendor’s modified one; tool-heavy multi-turn agent runs; 256k context; Ornith + MTP; Gemma’s single tool-call miss. 9-task eval = coarse filter.
2026-10-24 engine/model A/B suite (current)
The modular suite for engine/model comparisons lives in /data/docker/llama/bench/ (stages, run_suite.sh, logs /data/sources/llm-bench/logs/imgbench/); results and method in llm-engine-benchmark-2026-10-24. Outcome: strix-llama -ub 512 is prod.
Source: Wiki.js