Live numbers from the 2026-09-28 deploy: 13 s load to listening, RSS 30.6 GiB, ttft 549.8 ms / inter-token 24.2 ms on a short prompt, and a green contract battery (health, ready, /v1/models at 262,144, content + reasoning_content, tool_calls, SSE, and a two-turn tool loop). Also recorded: gufo accepts every request field the harness sends in extraBody and the full reasoning_effort set, both verified 200 — which is why models.yml's reasoningEffortMap fold is now optional rather than required, and why it is being kept anyway.
9.7 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reference | gufo Qwen3.8-27B UD-Q8_K_XL (DFlash2) on Dankclaw (frank-large) | The active frank-large runbook — gufo (gufo-org/gufo) v0.1.1, the Strix Halo inference engine, built from source on Dankclaw and serving unsloth/Qwen3.8-27B-GGUF:UD-Q8_K_XL with the z-lab DFlash2 Q4_K_M drafter on the gfx1151 iGPU: the from-source build and its two host workarounds, the one-session / full-window shape, what changed in the client contract versus llama.cpp, the measured prefill/decode trade, and the failure modes worth knowing. |
|
2026-09-28 |
frank-large — gufo Qwen3.8-27B UD-Q8_K_XL (DFlash2)
ACTIVE since 2026-09-28. Replaces frank-large-unsloth-qwen38-27b-q8xl (stock llama.cpp, the unsloth b11030 prebuilt), which had replaced frank-large-kairic-edge-qwen38-27b. Same host, same port (7770), same alias (
frank-large), same weights.
Identity
- Endpoint:
frank-largeat192.168.0.143:7770(Dankclaw). - Runtime: gufo — "the Strix Halo
inference engine", a vertical engine built for exactly this hardware
(Ryzen AI MAX+ 395 / Radeon 8060S,
gfx1151, unified memory). Pinned at v0.1.1 (commitb0f8673), built from source on the host to/home/dank/GitPackages/gufo-v0.1.1/. - Service shape: root systemd unit
scripts/frank-large.service(User=dank,LimitMEMLOCK=infinity), launched byscripts/serve-frank-large.shwith tunables fromscripts/frank-large.env.
gufo ships no prebuilt Linux binaries (the v0.1.0/v0.1.1 release assets are empty) and no Nix on this host, so the runtime is a source build. It is also young: v0.1.0 landed 2026-09-28, the same day as this cutover.
Why this engine
gufo's own measurement of the two engines on the same Qwen3.8-27B targets
(Strix Halo, 628ed18e vs llama.cpp b11069, greedy, DFlash2):
| Q8_K_XL, DFlash2 | gufo | llama.cpp | delta |
|---|---|---|---|
| prefill, depth 0 | 457.05 t/s | 333.85 t/s | +36.9 % |
| prefill, depth 131,072 | 237.24 t/s | 131.80 t/s | +80.0 % |
| decode, depth 0 (mixed) | 16.08 t/s | 15.00 t/s | +7.2 % |
| decode, depth 32,768 (mixed) | 14.41 t/s | 14.44 t/s | −0.2 % |
| decode, depth 65,536 (mixed) | 10.87 t/s | 12.62 t/s | −13.9 % |
| decode, depth 131,072 (mixed) | 8.87 t/s | 11.62 t/s | −23.7 % |
| cold load to HTTP-ready | 8.17 s | 36.47 s | 4.5× faster |
| peak memory @ 262,144 ctx | 50.58 GiB | 48.60 GiB | +4 % |
Read that honestly: prefill, load time and short-context decode improve; deep-context decode on the 8-bit target gets worse. The crossover on Q8 is around 32k of cached depth. frank-large runs one 262,144-token conversation, so a long agent session spends its life on the losing side of that line while a short turn wins. The Q4_K_XL target does not show the regression (gufo is +11.7 % to +17.0 % at every depth) — that is the honest reason to revisit the quantization separately from the runtime.
Build
scripts/build-gufo.sh reproduces the runtime end to end. It clones the
pinned tag, configures the release preset (HIP, --offload-arch=gfx1151),
builds, installs, and finishes with gufo diagnose. Two host facts it
encodes, both found the hard way on 2026-09-28:
- Ubuntu's
librocwmma-devmust not be installed. It ships a truncated rocWMMA header set (the public headers withoutrocwmma/internal/) into/usr/include, where it shadows AMD's complete copy under/opt/rocm/include. The first build died on'internal/accessors.hpp' file not foundfrom/usr/include/rocwmma/rocwmma.hpp, and a-Icannot fix it: in HIP mode the host compilation pass searches the system directories first. The package has no reverse dependencies; the script removes it. --gcc-install-dirmust point at GCC 15. Ubuntu 26.04 has/usr/include/c++/16, and the ROCm clang picks the newest tree, whose<atomic_wait.h>referencesstd::__detail::__notify_implat a symbol version the installedlibstdc++.so.6(GLIBCXX_3.4.35) does not export. The link then fails withundefined symbol. Pinning the headers to the GCC the runtime library came from fixes it.
Verify an installed runtime with bash scripts/build-gufo.sh --verify, or
gufo diagnose directly — it reports [PASS] plus the detected
architecture, driver and queue budget.
Shape
- Model:
unsloth/Qwen3.8-27B-GGUF:UD-Q8_K_XL— 27B dense, 29.30 GiB. Unchanged by the cutover, still fetched and sha256-verified byscripts/download-frank-large.sh. - Context: one session, full 262,144 tokens (the model's native window),
SESSIONS=1. The fleet's single stream is unchanged. - Spec method: DFlash2, gufo's adaptive block policy
(
--draft-policy adaptive,--draft-tokens 7). The drafter is the same z-labQwen3.8-27B-DFlash2-Q4_K_M(1.07 GiB). - Sampling: greedy (
--temperature 0), as every prior frank-large served. gufo's per-model recommendation for Qwen3.8 thinking is sampled (1.0 / 0.95 / top-k 20) — that is a separate decision, deliberately not bundled into a runtime swap. - Memory: gufo's own table puts the 8-bit target at 50.58 GiB peak with context capacity 262,144, against the iGPU's ~114 GiB GTT aperture.
Measured at the 2026-09-28 cutover
Live on Dankclaw after deploy.sh dankclaw --service frank-large:
- 13 s from
load_startedtolistening(target 8 s, drafter 2 s, session 3 s), against a 20-minuteLLM_WAITbudget — a redeploy no longer sits in a load wait. - RSS 30.6 GiB, VSZ 87.3 GiB; host
used81 GiB of 121 GiB, i.e. the same order as the llama.cpp deployment it replaced. - A short-prompt live request returned
Server-Timing: ttft;dur=549.8, inter_token;dur=24.2, max_inter_token;dur=166.9(≈41 tok/s). Short-prompt decode is gufo's winning regime; see the depth table above before quoting it as the endpoint's number. - Contract battery, all green:
/health200,/ready200,/v1/models→frank-largewithcontext_length 262144, a chat completion carrying bothcontentandreasoning_content, atool_callsresponse withfinish_reason: tool_calls, and SSE streaming.
Client contract — what actually changed
Everything the fleet depended on still holds: port 7770, alias frank-large,
reasoning_content, tool_calls, streaming SSE, and text-only (gufo
auto-discovers a mmproj beside the model; this payload has none).
The differences worth knowing:
- No custom chat template. gufo compiles the official Qwen Jinja into the
binary and takes no
--chat-template-file. The Qwen-Sharp v22.4.0 file this endpoint used with llama.cpp is no longer in the command line — the 2026-09-21 "73,600-token prompt" incident cannot recur, because there is no fallback template to land in. Thinking defaults to on atxhighwith prior reasoning preserved (--think auto --preserve-thinking on, spelled out in the serve script). reasoning_effortaccepts the full OpenAI set (none,minimal,low,medium,high,xhigh,max). Qwen-Sharp rejected anything outside{xhigh, medium, low}with an HTTP 500, which is whymodels.ymlstill carries areasoningEffortMapfold for this model. The fold is kept on purpose: removing it would silently move everyhighrole fromxhightohigheffort in the same commit as the runtime swap. Drop it as its own change once the effort curve is a decision rather than a side effect.- No KV-cache quantization flag. gufo picks its own KV dtype; there is
no
--cache-type-k. The oldCACHE_RAM=8192tunable is gone with it. Prompt reuse is on by default, and--cache-disk(restart-safe) is opt-in and currently off. - Health/readiness split:
GET /healthis process liveness and is what the deployer gates on;GET /readyis model/backend readiness.GET /metricsis Prometheus-format. - Long bodies:
--max-request-bytesdefaults to 8 MiB and unknown request fields are rejected rather than ignored.
Failure modes worth knowing
- A missing runtime is a deploy error, not a restart loop. The handler
gates on
LLM_LARGE_RUNTIMEbefore it stops anything, and the serve script exits with abuild-gufo.shpointer rather than exec'ing. - Host memory is the ceiling, and it is shared. frank-large and ComfyUI
both hold gfx1151 compute queues. gufo reads
/sys/class/kfd/kfd/proc/*/queues/*/typeand caps itself (GPU_MAX_HW_QUEUES, 2 resident forserve llm) so a full device time-slices instead of failing; four HIP processes is the device ceiling. - Load is seconds, not minutes (8 s measured cold), so a redeploy no
longer spends 20 minutes in
LLM_WAIT. - A v0.1.x runtime is a moving target. Rebuilds are not automatic —
RUNTIME_DIRnames a version, and the deployer will not silently substitute another.
Rollback
frank-large-unsloth-qwen38-27b-q8xl — the unsloth b11030 prebuilt is
still at /home/dank/GitPackages/unsloth-llama-b11030/ and the payload is
the same directory the current runtime reads. Roll back by reverting
RUNTIME_DIR (and the gufo-only tunables) in scripts/frank-large.env,
restoring the serve script's llama.cpp command, and redeploying.
Citations
- Runtime: https://github.com/gufo-org/gufo (pinned
v0.1.1, MIT) - Measured tables:
docs/models/qwen3.8-27b/BENCHMARKS.mdin that repo - API contract:
docs/SERVER.md; flags:docs/CLI.md - Build:
scripts/build-gufo.sh; serve:scripts/serve-frank-large.sh; tunables:scripts/frank-large.env - Payload:
scripts/download-frank-large.sh - Predecessor: frank-large-unsloth-qwen38-27b-q8xl