Enforces "one fact, one owner": technique pages keep mechanism, laws, traps and verdicts; per-endpoint shapes, digests and era measurements are cited to the endpoint page that owns them. Also repairs the four pointers the pass left empty (each verified against the cited owner before landing): - EMULATION dequant doubles host RAM (118 GiB -> ~238 GiB) -> [[frank-archon]] - 12.11 tok/s flat 304 -> 16,095 tokens -> [[Tcclaviger Fork Ops]] - bundled-head acceptance ladder 0.739/0.554/0.427/0.340 -> [[Qwen3.8 PP Deployment]] - llama.cpp PR #23897 dedup provenance -> [[qwen3.8-spec-matrix]] Replaces the retired-shape illustration in Llama Cpp Serving Sizing with the owned MiMo Q5_K_M row (6.40 GiB payload -> 20,530 MiB used), and unwraps a hard-wrapped [[Dankserver System Specs]] link that failed link integrity. Orphan census over the diff: 0 numbers lost (comma-insensitive match against the whole vault plus AGENTS.md).
12 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| reference | Tcclaviger Fork Ops | Operating the tcclaviger RDNA4 vLLM fork on dankserver (shape G era, rollback target since the 2026-10-05 FreeToken cutover) — the ad-hoc sweep harness, measured knob verdicts, sweep hygiene, the large-MoE serving recipe, and compile-cache persistence. |
|
2026-10-05T00:00:00-07:00 |
Tcclaviger Fork Ops
The tcclaviger RDNA4 vLLM fork (docker.io/tcclaviger/vllm@sha256:da4029666…,
vLLM 0.29.0.dev, GLM-5.3/Qwen-specialised with native MoE quant kernels and a
first-class expert-offload planner) served frank-archon at shape G until
the 2026-10-05 FreeToken cutover; it remains the rollback target
(git tag frank-archon-vllm-shapeG-20261003). Full plan law and VRAM
arithmetic: RDNA4 MoE Expert Offload VRAM Budget; boot forensics:
vLLM Boot Forensics and Config Interrogation; window discipline:
LLM Bench Windows and Measurement.
The ad-hoc sweep harness (dankserver)
Serve script /home/dank/serve_qwen_fp8.sh with env hooks: SPEC (MTP
depth), TUNABLE (TunableOp), PREFETCH, UTIL, MAXLEN, KV_BYTES,
MNBT, UVA_TOK, GATHER_C/GATHER_L (R4D_LRU gather), TELEM
(R4D_LRU_TELEMETRY), PROFDIR (torch profiler bind-mount + --profiler-config
JSON). The script re-copies the harness (mtp_measure.py, bench_iter.py)
into every fresh container — podman cp files die on container recreate.
- Measure ONLY via usage counters:
mtp_measure.py(3 depths) ormtp_measure_short.py(166 ctx).decode = completion_tokens/(wall − ttft); chunk counting is INVALID under spec decode. - Jobs:
bash /home/dank/job.sh start NAME CMD…/wait NAME SECS 40/out NAME(Remote Job Runner). - Validity check on ANY speed result:
completion_tokens == max_tokens(else repetition-halt or early EOS), finish_reason, and inspect the text —bench_iterprompts are repeated word-lists +!padding, loop-prone. A loop makes LRU hits ~100% → PCIe traffic vanishes → fake 3–4× decode. Acceptance swings 48–61% run-to-run — noise; decode is the metric. - Each arm = full reload: ~8.5 min cold, ~12 min with measurement.
- Readiness gate:
podman logs <c> 2>&1(stdout+stderr merged) forApplication startup complete— it is on STDERR; an unmerged grep can never match and burns the whole wait timeout. - GPU util ~0% during load/compile is NORMAL (weights + CUDA-graph capture are CPU-side); VRAM climbing is the load indicator.
- Config edit discipline: the serve script is patched by scp'd python
scripts with asserts (anchor must exist, addition must not);
bash -nafter every patch.
Measured knob verdicts (2026-09-29 campaign)
Incumbent: SPEC=4 PREFETCH=1 UTIL=0.98 MAXLEN=32768 KV_BYTES=2147483648 TUNABLE=0, stock gather 8×16 → 26.80/25.15/26.81 tok/s @ 166/1087/4064 ctx.
| Knob | Verdict | Evidence |
|---|---|---|
Gather geometry R4D_LRU_GATHER_{CHUNKS,LANES} |
RULED OUT | 16×32 worse (~24); 32×64 tie (26.6). The 9.5 vs 22.7 GB/s read-path gap is per-transfer structure (~105 µs/slab vs 78 ideal), not a tunable knob |
| MTP depth | RULED OUT | SPEC=3 ~9% worse; SPEC=6 collapses (13.5–19 tok/s, acceptance 17.4%) — also proves UVA read-through (crosses at step tokens > R4D_LRU_UVA_TOKENS=5) is SLOWER than copy-in |
| TunableOp | REJECTED | CLAV_TUNABLEOP_SWEEP=1 silently SKIPPED under expert offload unless CLAV_TUNABLEOP_WITH_OFFLOAD=1; adds ~7 min/load, persists nothing (container-local), and CORRUPTS NUMERICS (loops, repetition-halt, fake 79.8 tok/s @ 96.5% acceptance on degenerate completions). Any "3× win" with early-EOS + absurd acceptance = the loop artifact |
| MNBT | neutral at 8192 vs 2048 | small values re-chunk prefill only (hurts TTFT, never decode — decode step = max-num-seqs × (spec+1) tokens). No ubatch concept in vLLM |
Decode on this stack is PCIe-gather-bound (~30% GPU duty cycle), so batch-shaped compute knobs move ~nothing. Measured with no spec: 12.11 tok/s FLAT from 304 to 16,095 context tokens — KV attention is not the cost, so a context-slope hunt on this stack is null by construction.
The R4D_*/CLAV_* knob family (QSA_, MHC, ROUTE, ACT_QUANT, AR_QUANT,
SILU_QUANT) are kill-switches defaulting ON, not perf dials; real levers are
the R4D_LRU_ family, TunableOp (rejected), R4D_LRU_TELEMETRY, and spec
depth.
Telemetry gotchas: --profiler-config takes a JSON blob, not separate
flags; torch_profiler_with_stack defaults TRUE — a full measure inside a
profile window OOM-kills the engine worker (~40 GB trace buffer; kernel
kills python3 at ~95 GB anon-rss). Keep windows to ~15 s / one depth
(mtp_measure_short.py). telemetry_report (expert_cache_rank<N>.json)
fires ONLY from the worker's profiler-stop path; worker-side stop can hang
5 min on ROCm/kineto. No alternative trigger exists. The LRU hit rate measured 82.45% — NOT the ~27% the arena-fraction arithmetic implies; temporal reuse dominates, so never infer miss rates from resident-slot fractions.
Sweep hygiene (fork-specific preflight)
- Knob landed: for each
-eenv knob, confirm in-containerpodman exec … env(or the engine log's confirmed-values line). A knob the fork silently ignores produces a "parity" arm that is really the default — the v1 gather sweep lost all three arms to exactly this (GATHER_C/GATHER_L silently dropped, all arms ran stock 8×16). - Prefetch uniformity: every arm in a sweep MUST carry the same expert-prefetch setting. The 2026-09-29 campaign measured losing arms with prefetch ON and incumbents OFF; untaxed, its verdicts inverted (no-spec 12.11→41.47; gather 32×64 parity→+18.7%). Never re-read a taxed verdict.
- Spec arms must prove engagement: engine log
SpecDecoding metrics: Mean acceptance length …andcurl :7770/metrics | grep vllm:spec_decode_. Zero such lines = MTP off. - Boot-fail fast-detection: poll
podman psINSIDE the health loop; a refused boot dies in one poll instead of 20 min of health waits. Capture8 lines of
podman logson failure — the root cause (e.g. a SEQS init refusal) lives higher up. - Report per-depth tables, never one number: g32×64's win grows with depth (54@1k, 39.5@short) — a single 4064 median hides the short-ctx cost. TTFT rows are noisy ±0.15 s and non-monotonic across depths; compare same-ctx rows across arms only.
- Generate ≥256 tokens per sample (at 8 tokens inter_token is first-token noise).
Boot-log facts survive measure failures: KV pool size (GPU KV cache size),
arena slots (expert cache: … -> N slots), and the spec-reservation ladder
(MTP3 766,666 / MTP4 729,545 / MTP6 665,263 tokens) print at BOOT — a
measure-stage bug costs decode tables but not boot-log findings.
MTP depth-brittleness law (2026-10-02, all arms rc=0): MTP3 on this fork
is depth-brittle — 47.01 t/s at 166 tokens (47.88 at temp 0.7) but 23.09 at
4064, vs no-spec baseline 37.02 / 33.99. MTP3 + SEQS 16 + MNBT 4096 + util
0.95 + ladder [4..32] = best overall 37.04 / 38.61 t0.7 and keeps 33.15 at
4064. --expert-precise-memory is load-bearing for MTP (same arm with it
OFF = worst arm, 19.81 at 4064). Every spec arm costs KV (398,658 → 313,002
tokens). Acceptance is real: mean length 2.4–2.8, per-position
0.76/0.55/0.33, avg 52–57%. Next lever named by the engine: MNBT 4096 is
exactly SEQS×(n+1) (suboptimal warning) → try 8192.
Serving a model larger than VRAM (dankserver recipe)
Dankserver's card count, per-card VRAM and host RAM are in Dankserver System Specs;
torch.cuda.device_count() returns 3 on this box and summing total_memory overstates it
badly (the Raphael iGPU is in the list — reading discipline: Llama Cpp Serving Sizing).
Everything else about running this image — the quant-kernel gate that decides
which checkpoints can serve at all, the entrypoint contract, the known-good
invocation, the /dev/dri and memlock traps, the util and max-model-len arena
traps, the --ipc=host / -d stdout traps and the gated-fetch discipline — is
written once on RDNA4 Container Serving, and the plan arithmetic behind the
arena/KV traps is RDNA4 MoE Expert Offload VRAM Budget's. Three findings
stay here because this harness produced them:
- The KV reserve undercounts hybrid-attention models ~2× (the planner's
B/token figure against ~18,000 real: the Mamba state is a fixed per-sequence
cost). Fix by pinning the pool:
--kv-cache-memory-bytes. --expert-offload-memcaps the HOST side, not the VRAM arena — structurally orthogonal to--expert-precise-memory(verified in-container 2026-10-05: precise-memory only swaps the GPU overhead term, expert_offload_mem only sets the host bound; they rejoin only insideplace_experts, and the plan rewritesexpert_offload_memback to the cap the plan met, so plan and allocation cannot drift).- Check whether the stack supports the model natively before porting an
overlay. The image already registered
Glm5NextForConditionalGeneration,Qwen4ExpForCausalLMand both MTP variants — chasing four missing symbols through two image tags to bring an overlay up was entirely wasted work.
The checkpoint this recipe was verified on is
orcarouter/Qwen3.8-Flash-Next-Uncensored-FP8 (gated; 172.8 GiB, 131 shards,
Qwen4ExpForConditionalGeneration, 48 layers, 512 experts top-10, multimodal,
native 262,144) — an frank-archon era payload.
Compile-cache persistence (survives podman rm -f)
Serve scripts that recreate the container discard the writable layer, so
every boot re-pays compile/JIT (frank-archon: torch.compile took 181.20 s
cold, of which 173 s was one graph).
- Prove it and locate it: fresh container vs live
(
podman run --rm --entrypoint bash IMG -c "ls -la /root/.cache"vspodman exec LIVE bash -c "du -sb /root/.cache/*; find /root/.cache -type f | wc -l"). vLLM cache root:VLLM_CACHE_ROOT(default/root/.cache/vllm,torch_compile_cache/); a HIP runtime adds/root/.cache/comgr. - Mount the PARENT, not the leaf — one bind on
/root/.cachepersists both trees, safe whenever the image ships no such directory (step 1 proves it; otherwise you would be hiding baked state). Wire as an opt-in tunable:mkdir -p "$CACHE_DIR"BEFORE the mount, then${CACHE_DIR:+-v "$CACHE_DIR":/root/.cache}. Host path outside the checkout. - Verify with two consecutive boots — cold
Compiling a graph … takes N s, warmDirectly load the compiled graph(s) for compile range (…) from the cachewithtorch.compile tookin single-digit seconds. - Traps: the cache key includes the compile RANGE — an MNBT change costs
ONE recompile, not a permanent tax; do not claim a proportional boot cut
(time to
/healthis dominated by weight loading: 490 s warm vs 188 s cold compile); stale entries are misses, not wrong answers (version + config hashed); if the serve script is seam-gated, assert the mkdir and the exact mount target.
Plan-line verification checklist (after any fork deploy)
The journal one-liner that reads the plan lines (digit-anchored grep -oE,
because plain grep truncates those columns to 17.) and the post-deploy
verification order — plan vs captured graph memory, GPU KV cache size vs the
ask, per-card rocm-smi high-water, NRestarts = 0, VLLM_CUDAGRAPH_* present
in the container env, then a real completion from a PEER because
curl localhost:7770/health inside an ssh session on the host can return 000
and look like an outage — are step 3 of
RDNA4 MoE Expert Offload VRAM Budget §7. Run that; do not re-derive it
here.
Related
- RDNA4 MoE Expert Offload VRAM Budget — the plan law this harness tunes
- vLLM Boot Forensics and Config Interrogation — journal forensics for these boots
- LLM Bench Windows and Measurement — window discipline and bash laws
- Model Swap and Rollback — where the fork sits in the swap history
- Remote Job Runner — the job.sh harness referenced above