docs(frank-archon): record the bf16 KV shape, its measured cost, and the probe
Runbook section `2026-10-11 — unquantized KV at 2 x 200,000`: the dtype law (only bf16|fp8, no K/V split; the QSA block key is dtype-fixed, which is why bf16 costs 1.89x and not 2x), the pool formula that reproduces both live boots within 0.1%, the seqs-3-to-2 provenance (the tcclaviger fork's torch.compile constraint, not radiance's), the boot ledger, and the A/B. The A/B, fp8 control arm through a transient FRANK_ARCHON_ENV_FILE drop-in: prefill -29% (4,379 -> 3,126 cold), TTFT at the full window +25% (the 2 x 197k pair: 110.5 s -> 138.1 s), decode inside the +-3% band on two of three passes, draft acceptance UP 0.661 -> 0.740. The price is prefill, not decode. Open call for Frank: keep exact KV, or take the cheap fp8 2 x 200k fit (pool 3,648). Also corrects two stale index entries (w4dn8 said STAGED, fp8-native said ACTIVE), adds the worklog entry, and commits the verification tool as scripts/probe-frank-archon-kv.py — it carries the probe law that cost two false negatives: radiance answers in reasoning_content, so a chat probe with a small budget reads as empty content + finish_reason stop on a healthy server. Tests 368/368.
This commit is contained in:
@@ -97,14 +97,161 @@ policy; 173 GiB, purge when the window closes).
|
||||
|
||||
## The shape (`scripts/frank-archon.env`)
|
||||
|
||||
Unchanged from the FP8-native era: TP=2 + `wht6`, `--max-num-seqs 3`,
|
||||
`--max-model-len 200000`, MNBT 2048 (the MTP resonance law — 2560
|
||||
collapses decode to 2.6–7.7 t/s), fp8 KV, `expert_tiered` host pool
|
||||
40960 (the load-bearing floor), `--ngram-placement ram`, froggeric
|
||||
TP=2 + `wht6`, `--max-model-len 200000`, MNBT 2048 (the MTP resonance law —
|
||||
2560 collapses decode to 2.6–7.7 t/s), `--ngram-placement ram`, froggeric
|
||||
v22.5 template override. `MODEL_FILE` points at
|
||||
`/home/dank/models/rad/qwen4exp-swift15-w4dn8-i8-hc8m.rad` (**116,416
|
||||
MiB measured**); the serve size floor `FRANK_ARCHON_RAD_MIN_MIB` moves
|
||||
177000 → **110000**.
|
||||
`/home/dank/models/rad/qwen4exp-swift15-w4dn8-i8-hc8m.rad` (**116,416 MiB
|
||||
measured**); the serve size floor `FRANK_ARCHON_RAD_MIN_MIB` moves
|
||||
177000 → **110000**. Concurrency and the KV cache moved on 2026-10-11; that
|
||||
change is documented in its own section below.
|
||||
|
||||
## 2026-10-11 — unquantized KV at 2 × 200,000
|
||||
|
||||
The ask: two concurrent 200,000-token conversations on exact (unquantized)
|
||||
attention state. The fp8 pool backed 3,543 MiB → **386,904 tokens = 1.93
|
||||
sessions of the served window**, so two full-height conversations overflow it
|
||||
and the scheduler preempts the overflow to the host/disk prefix tiers
|
||||
(re-prefilling on return). Measured, that overflow is survivable — the fp8
|
||||
shape passed the same 2 × 197k pair probe — so this is a **headroom** change,
|
||||
not the repair of a hard failure. The hard limit the engine states is per
|
||||
request, not per pair: a request longer than the pool's token count is
|
||||
*"accepted by the API and then refused as too large to ever fit — this is a
|
||||
hard limit, not a backing ratio"*, and at 200,000 ≤ 386,904 no single request
|
||||
ever hit it.
|
||||
|
||||
### The dtype law
|
||||
|
||||
`--kv-cache-dtype` takes **only `bf16 | fp8`**: one `kv_dtype` for the whole
|
||||
cache. llama.cpp's exact-K / quantized-V pair (what frank-zealot runs as
|
||||
`--cache-type-k f16 --cache-type-v q8_0`) has **no radiance equivalent** — the
|
||||
rung under bf16 is fp8 on both halves. Evidence: the flag table in the image
|
||||
itself (`--kv-cache-dtype takes bf16 or fp8, not '%s'`) and the absence of any
|
||||
`cache-type-k`/`-v` symbol in the binary.
|
||||
|
||||
bf16 costs **1.89× fp8, not 2×**, and the reason is in the group table:
|
||||
|
||||
| Group | fp8 page | bf16 page | cost per token, per rank |
|
||||
|---|---|---|---|
|
||||
| `kv_attn` — 13 full-attention layers, 4-token blocks | 26.00 KiB | 52.00 KiB | 6.5 → 13.0 KiB |
|
||||
| `kv_qsa_bkey` — 13 layers, the QSA indexer keys | 3.25 KiB | **3.25 KiB** | 0.8125 KiB, dtype-fixed |
|
||||
| `kv_gdn_state` 54 MiB × 2 copies per sequence (+ conv/tail/ple) | per slot | per slot | ≈ 110 MiB **per sequence** |
|
||||
| prefix checkpoints 8 × 55.99 MiB (inside the pool) | 448 MiB | 448 MiB | fixed |
|
||||
|
||||
→ `pool_mib ≥ tokens × 13.8125 KiB + 110 × seqs + 448`. The formula reproduces
|
||||
both live boots: fp8 `(3543 − 330 − 448) → 387,240` vs the ledger's 386,904;
|
||||
bf16 `(6912 − 220 − 448) → 462,946` vs the ledger's **462,752**. It is encoded
|
||||
as a test seam (`the KV pool backs seqs x max-model-len at the declared cache
|
||||
dtype`) so a future resize cannot silently under-provision the pool.
|
||||
|
||||
### Why the weights slab pays — and why that is not pure loss
|
||||
|
||||
The two VRAM budgets are one budget: card 31,856 MiB, minus the 1,710 MiB a
|
||||
boot consumes outside both (driver context, the 990 MiB activation arena,
|
||||
hardware queues, headroom, step staging), minus 1,024 MiB kept free ⇒
|
||||
**`weights + kv ≤ 29,120 MiB`**. Paying for a 6,912 MiB pool therefore cuts the
|
||||
resident slab 26,071 → 22,208 MiB (−14.8 %), and the evicted experts spill
|
||||
into the pinned host pool (40,960 → 44,928 MiB per rank; ledger: pinned pool
|
||||
slots 7,190 → 10,375). The pinned-RAM ledger rises to ≈147 GiB, so the TTM
|
||||
floor moved 140,000 → 150,000 MiB (the kernel cap is 204,800).
|
||||
|
||||
Half of that loss is refunded by an engine behaviour worth knowing: **idle KV
|
||||
VRAM is the expert cache's spillover**. The fp8 pool lent 2.69 GiB to the expert
|
||||
slab; the bf16 pool lends **6.08 GiB** (`mover: 5146 slots can be lent out of
|
||||
the KV cache`). On a llama.cpp endpoint KV is inert storage; on radiance it is
|
||||
a competing cache, and every KV resize is also an expert-residency resize.
|
||||
|
||||
### seqs 3 → 2
|
||||
|
||||
`--max-num-seqs 3` was never a radiance requirement: it is the tcclaviger vLLM
|
||||
fork's torch.compile constraint (`ConstraintViolationError: Constraints
|
||||
violated (L['query_start_loc'].size()[0])`), retired with that runtime — see
|
||||
[[dankserver-qwen38-fp8-expert-offload-tuning]]. Radiance booted seqs 2 in the
|
||||
fp8-native era, and the 2026-10-06 decode sweep measured seqs 2 and 3 tied
|
||||
inside the ±3 % noise floor. Two slots × the window is the capacity contract;
|
||||
it also saves 110 MiB of per-slot recurrent state and drops the fused TP
|
||||
all-reduce to 2 × 3 = 6 rows, i.e. deeper inside the 25-row bound at which the
|
||||
wht6 wire is bit-exact.
|
||||
|
||||
### Boot ledger (deployed 2026-10-11, commit `0bf26b0`)
|
||||
|
||||
```text
|
||||
kv cache 6.75 GiB 349% of it -- backs 2 sequences all at 200000
|
||||
tokens at once, which is the worst case
|
||||
vram_weights 21.69 GiB stated by --vram-weights-mib
|
||||
vram_kv 6.75 GiB stated by --vram-kv-mib
|
||||
unclaimed 2.03 GiB
|
||||
kv_attn full 13 layers block 4 tok page 52.00 KiB 115688 blocks = 5.74 GiB (462752 tokens)
|
||||
kv_qsa_bkey full 13 layers block 4 tok page 3.25 KiB 115688 blocks = 367.17 MiB (462752 tokens)
|
||||
load: rank 0, mover took 21.69 GiB, weights pool 147.00 KiB free of 21.69 GiB
|
||||
mover: 5146 slots can be lent out of the KV cache (6.08 GiB)
|
||||
card 0 settled at 1.85 GiB free
|
||||
serving on http://:::7770
|
||||
```
|
||||
|
||||
### Verification (live service, no scratch container)
|
||||
|
||||
| Check | Result |
|
||||
|---|---|
|
||||
| `/health`, `/v1/models` | 200 `{"status":"ok","model":"frank-archon"}`; served id `frank-archon` |
|
||||
| 2 × ~197k concurrent, a unique marker buried at the head of each | **both answered their own marker exactly** — 196,919 + 196,918 = 393,837 tokens resident, above the fp8 pool's 386,904 and inside bf16's 462,752; walls 138.1 s / 66.2 s, `finish_reason: stop`, prefill 2,747 / 2,991 t/s |
|
||||
| decode at 51.5k depth, 512 tokens, greedy | 94.1 cold / 102.3 warm / 117.6 on a prefix-cache hit t/s; draft acceptance 0.7284 / 0.7525 (fp8 control at cutover: 0.7246) |
|
||||
| fp8 control arm, same probes (`scripts/probe-frank-archon-kv.py`) | table in the next section |
|
||||
|
||||
Probe law re-learned, worth recording: radiance routes the thinking block to
|
||||
`reasoning_content`, so a chat request whose budget is spent inside `<think>`
|
||||
comes back with **empty `content` and `finish_reason: stop`** — a probe that
|
||||
forbids thinking (`chat_template_kwargs.enable_thinking=false`) and reads both
|
||||
fields is the only honest shape. The first pair probe scored 0/2 on exactly
|
||||
that artifact, not on a KV fault.
|
||||
|
||||
### Measured cost — A/B on the live service
|
||||
|
||||
Method (no scratch container, no mask — the unit file is a relink symlink and
|
||||
`mask` refuses it): write a variant env file on the host
|
||||
(`/home/dank/frank-archon-fp8control.env`), point a transient drop-in at it
|
||||
(`Environment=FRANK_ARCHON_ENV_FILE=…`; drop-ins are read AFTER the unit's own
|
||||
`Environment=` lines, so they win), `daemon-reload`, restart, probe, delete the
|
||||
drop-in, restart. Control = the deployed 2026-10-08 shape, verified from
|
||||
`podman inspect` argv (`--kv-cache-dtype fp8 --vram-weights-mib 26071
|
||||
--vram-kv-mib 3543 --max-num-seqs 3`) and the ledger page size (26.00 KiB).
|
||||
Identical probes, same salts, loopback, greedy, 512 generated tokens.
|
||||
|
||||
| Probe | fp8 control (26071/3543, seqs 3) | bf16 deployed (22208/6912, seqs 2) | Δ |
|
||||
|---|---|---|---|
|
||||
| prefill 51.5k, cold | 4,379 t/s | 3,126 t/s | **−29 %** |
|
||||
| prefill 51.5k, warm | 4,864 t/s | 3,333 t/s | **−31 %** |
|
||||
| decode 51.5k, cold | 124.1 t/s | 94.1 t/s | −24 % |
|
||||
| decode 51.5k, warm | 99.2 t/s | 102.3 t/s | +3 % |
|
||||
| decode on a prefix-cache hit | 127.7 t/s | 117.6 t/s | −8 % |
|
||||
| draft acceptance, mean of passes | 0.661 | 0.740 | **+12 %** |
|
||||
| 2 × 196,919 concurrent pair | both markers HIT, 110.5 s | both markers HIT, 138.1 s | +25 % wall |
|
||||
|
||||
Read it as: **the price of exact KV on this engine is prefill, not decode.**
|
||||
Prefill is expert-bandwidth-bound and the resident slab is 14.8 % smaller, so
|
||||
time-to-first-token at the full window rises ~25 % (the pair: 110 s → 138 s);
|
||||
both prefill passes agree, far outside the ±2 % prefill noise floor. Decode is
|
||||
inside the ±3 % band on two of three passes (warm +3 %, hit −8 %); the cold-pass
|
||||
−24 % is the largest single number, the least reproducible, and it moves the
|
||||
same direction as prefill — the cold arm is paying expert streaming, not
|
||||
attention. Spec-decode acceptance IMPROVED ~8 points (0.661 → 0.740): exact
|
||||
attention state makes the target agree with the MTP drafter more often, which
|
||||
pays on every token of every conversation, and it is the strongest argument for
|
||||
the shape.
|
||||
|
||||
Open call (Frank): keep exact KV at the prefill cost, or take the cheap fp8
|
||||
variant — `--vram-kv-mib 3,648` + `--max-num-seqs 2` fits 2 × 200,000 at fp8
|
||||
for a 105 MiB pool bump and ≈ no decode cost. The tool is committed:
|
||||
`scripts/probe-frank-archon-kv.py` (run it on Dankserver; it rebuilds its
|
||||
prompts from the repo checkout there).
|
||||
|
||||
### Rollback
|
||||
|
||||
Revert `scripts/frank-archon.env` to the fp8 pair (26071/3543, fp8, seqs 3,
|
||||
host pool 40960, prefix host 4096) and redeploy: no payload change, boot ~2 min.
|
||||
The KLD gate scored at the fp8-KV shape, so a bf16-KV production runs *away*
|
||||
from the scored configuration — bf16 can only reduce the attention-state
|
||||
error, and a re-score is a drained-window job if the gate agreement is ever
|
||||
needed in the record.
|
||||
|
||||
## Gates (measured at cutover)
|
||||
|
||||
|
||||
@@ -152,11 +152,17 @@ frank-zealot, port 7771]
|
||||
target; payload on disk; owns the measured boot-pair table)**: the same
|
||||
runtime and the same 2 x 200,704 + f16 KV shape one quant rung lower —
|
||||
104.8 tok/s, 3,571 MiB true free
|
||||
- [[frank-archon-radiance-swift15-w4dn8]] — **STAGED (campaign running)**:
|
||||
- [[frank-archon-radiance-swift15-w4dn8]] — **ACTIVE since 2026-10-08**:
|
||||
Swift1.5 Qwen3.8-Flash-Next BF16 → GPTQ-calibrated W4Dn8 `.rad` on radiance
|
||||
1.0.13 (recipe + 10M-token calibration + KLD gate vs the BF16 container);
|
||||
replaces the FP8-native payload when the gates pass
|
||||
- [[frank-archon-radiance-qwen38-native-fp8]] — **ACTIVE since 2026-10-05**
|
||||
the FP8-native payload remains the rollback. **2026-10-11: the KV cache is
|
||||
UNQUANTIZED (bf16) at 2 x 200,000** — pool 3543 → 6912 MiB (386,904 →
|
||||
462,752 tokens), weights slab 26071 → 22208, host pool 44928,
|
||||
`--max-num-seqs 2`. bf16 costs 1.89x fp8 per token (the QSA block key is
|
||||
dtype-fixed, so it is not a clean 2x); measured price is prefill (-29%),
|
||||
NOT decode, and spec-decode acceptance rose 0.661 → 0.740.
|
||||
- [[frank-archon-radiance-qwen38-native-fp8]] — **RETIRED 2026-10-08 (the
|
||||
w4dn8 swap replaced it; its `.rad` stays on disk as the rollback)**
|
||||
(root systemd unit, port 7770): the StillDeadcode **radiance** engine
|
||||
(C++/HIP, libr4d gfx1201 kernels, digest-pinned 287 MiB image, engine as
|
||||
the image entrypoint) serving the OFFICIAL `Qwen/Qwen3.8-Flash-Next-FP8`
|
||||
|
||||
@@ -1598,3 +1598,56 @@ every restart since the cutover.
|
||||
so the honest claim is ~184 s of inductor/AOT build recovered per restart —
|
||||
not a proportional boot cut.
|
||||
|
||||
## 2026-10-11 — frank-archon: unquantized (bf16) KV at 2 × 200,000
|
||||
|
||||
- Ask: two concurrent 200,000-token conversations on exact attention state.
|
||||
Sized from the live fp8 boot ledger, not arithmetic: the paged groups cost
|
||||
7.3125 KiB/token per rank (`kv_attn` 26.00 KiB per 4-token block +
|
||||
`kv_qsa_bkey` 3.25), so the 3,543 MiB pool bought 386,904 tokens = **1.93
|
||||
sessions of the served window**.
|
||||
- Engine door: `--kv-cache-dtype` takes ONLY `bf16|fp8` — one dtype for the
|
||||
whole cache, so llama.cpp's exact-K / quantized-V pair (what frank-zealot
|
||||
runs) has **no radiance equivalent**. Measured bf16 rate is **13.8125
|
||||
KiB/token = 1.89× fp8, not 2×**: the QSA block key (13 layers, 3.25 KiB per
|
||||
4 tokens) does not follow the dtype. Pool formula
|
||||
`tokens × rate + 110 MiB × seqs (recurrent state) + 448 MiB (prefix
|
||||
checkpoints)` reproduces both boots within 0.1 %, and is now a test seam.
|
||||
- Deployed (`0bf26b0` + docs): pool 3543 → **6912** MiB (462,752 tokens; ledger
|
||||
"backs 2 sequences all at 200000 tokens at once"), weights slab 26071 →
|
||||
22208, host pool 40960 → 44928 (the evicted experts land there; pinned pool
|
||||
slots 7,190 → 10,375), prefix host 4096 → 8192 (the entry grows 58.50 →
|
||||
110.50 KiB), TTM floor 140000 → 150000 (pinned ledger ~147 GiB, cap 204,800).
|
||||
`weights + kv` pinned to the measured ceiling **29,120 MiB/card**; cards
|
||||
settled 1.85 GiB free — more than the fp8 boot's 1.39, because the total
|
||||
claim dropped. Half the cost is refunded by the engine: idle KV VRAM is the
|
||||
expert cache's spillover, and the bigger pool *lends* 6.08 GiB where the fp8
|
||||
pool lent 2.69.
|
||||
- `--max-num-seqs 3 → 2`: the fleet's "seqs 2 cannot boot" law is the retired
|
||||
tcclaviger vLLM fork's torch.compile `query_start_loc` constraint, not
|
||||
radiance's — radiance booted seqs 2 in the fp8-native era and the 2026-10-06
|
||||
sweep had 2 and 3 tied inside ±3 %. Bonus: the fused all-reduce is declared
|
||||
over 2 × (1+2) = 6 rows, inside the 25-row bound where the wht6 wire is
|
||||
bit-exact.
|
||||
- Verified live (no scratch container, no bench): `/health` 200, served id
|
||||
`frank-archon`; 2 × 196,919 concurrent conversations each answered the
|
||||
marker buried at the head of its own prompt (393,837 tokens resident, above
|
||||
the fp8 pool's 386,904); decode at 51.5k depth 94.1 cold / 102.3 warm / 117.6
|
||||
prefix-hit t/s, draft acceptance 0.7284 / 0.7525.
|
||||
- fp8 control arm through a transient `FRANK_ARCHON_ENV_FILE` drop-in (the
|
||||
frank-zealot ubatch method, argv + ledger page size verified): prefill
|
||||
**−29 %** (4,379 → 3,126 cold, 4,864 → 3,333 warm), decode inside the noise
|
||||
band on two of three passes, TTFT at the full window **+25 %** (the pair:
|
||||
110.5 s → 138.1 s), draft acceptance **up 0.661 → 0.740**. The price is
|
||||
prefill — a 14.8 % smaller resident slab, and prefill is the pass that
|
||||
touches every expert — the gain is exact state plus acceptance. **Open call
|
||||
for Frank:** keep bf16, or take the cheap fp8 2 × 200k fit (pool 3,648 MiB,
|
||||
≈ free) and leave KV quantized.
|
||||
- Harness law re-learned: radiance puts the thinking block in
|
||||
`reasoning_content`, so a probe that reads `content` on a small budget sees
|
||||
empty text with `finish_reason: stop` — a healthy server scored 0/2 until the
|
||||
probe set `chat_template_kwargs.enable_thinking=false`. Tool committed as
|
||||
`scripts/probe-frank-archon-kv.py`.
|
||||
- Tests 368/368, e2e 33/33 (one unrelated homepage retry). Docs:
|
||||
[[frank-archon-radiance-swift15-w4dn8]], and the LLM index entry corrected
|
||||
(the w4dn8 entry said STAGED, the fp8-native one said ACTIVE).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user