frank-archon: the slab is a threshold, and decode is where slots cost
Measured, 512 tokens, greedy, cold, at the deployed 3 x 200,000 fp8 shape: prefill 22,208 -> 3,397, 24,000 -> 3,290, 25,600 -> 3,290 t/s at 43.5k — the third slab step bought nothing, so the slab is a threshold whose cliff is the 2026-10-11 arm at 26,071 (4,379), not a slope. Decode ladder: 99.0 t/s single-stream at 43.5k, 93.3 at 197k (nearly window-free), and 3 concurrent streams 113.9/43.3/10.9 = 18.4 t/s aggregate — the slot count is paid in decode concurrency, the axis the shape hunt never measured because probe leg B generates 24 tokens. probe-frank-archon-kv.py gains leg D (N-stream decode, 512 tokens, per-stream + aggregate) so no resize is priced on prefill alone.
This commit is contained in:
@@ -550,10 +550,18 @@ all at 200000 tokens at once, which is the worst case` — `kv_attn` page
|
|||||||
every 1,792 MiB buys ~1,300 resident experts, and the pinned host pool hands
|
every 1,792 MiB buys ~1,300 resident experts, and the pinned host pool hands
|
||||||
the same experts back: 8,893 → 7,580 slots); `unclaimed 477.30 MiB`, cards
|
the same experts back: 8,893 → 7,580 slots); `unclaimed 477.30 MiB`, cards
|
||||||
settled ~336 MiB free against the engine's 209.19 MiB floor, KV lending
|
settled ~336 MiB free against the engine's 209.19 MiB floor, KV lending
|
||||||
4.22 GiB to the expert cache. Prefill tracks this slab: the 24,000 → 25,600
|
4.22 GiB to the expert cache. Prefill tracks this slab only up to a
|
||||||
step measured +8.9 % single-stream (3,290 → 3,584 t/s at 43.5k) and +17.6 %
|
**threshold**: 22,208 → 3,397 and 24,000 → 3,290 t/s at 43.5k are one band
|
||||||
concurrent (3-way 197k aggregate), so the pinned host pool is the slow path and
|
(±3 %), and the 25,600 arm measured **3,290** — the third step bought nothing
|
||||||
every MiB moved from RAM onto the card is throughput.
|
(the 3,584 arm did not reproduce at 3 slots); the cliff is at ~26 GiB
|
||||||
|
(26,071 → 4,379 on 2026-10-11's arm), so below that the slab is a threshold,
|
||||||
|
not a slope.
|
||||||
|
|
||||||
|
**Decode ladder (2026-10-13, 512 tokens, greedy, this shape)**: 99.0 t/s
|
||||||
|
single-stream at 43.5k, 93.3 at 197k — decode is nearly window-free (−6 % for
|
||||||
|
4.5× depth); **3 concurrent streams give 113.9/43.3/10.9 t/s = 18.4 t/s
|
||||||
|
aggregate**, so the slot count is paid in decode concurrency (a fused-step
|
||||||
|
lottery), not in prefill; leg D of `probe-frank-archon-kv.py` measures it.
|
||||||
|
|
||||||
Shape notes carried from the fp8-native era and unchanged: wht6 gains,
|
Shape notes carried from the fp8-native era and unchanged: wht6 gains,
|
||||||
MNDT 2048 law (2560 collapses decode to 2.6–7.7 t/s), the 64 GiB disk
|
MNDT 2048 law (2560 collapses decode to 2.6–7.7 t/s), the 64 GiB disk
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ No scratch container, no mask: the service under test is the service.
|
|||||||
|
|
||||||
ssh dankserver 'python3 /home/dank/serverAppConfigs/scripts/probe-frank-archon-kv.py'
|
ssh dankserver 'python3 /home/dank/serverAppConfigs/scripts/probe-frank-archon-kv.py'
|
||||||
|
|
||||||
Three probes, in increasing cost:
|
Four probes, in increasing cost:
|
||||||
A decode at depth — one ~51k-token chat completion, 512 tokens, greedy.
|
A decode at depth — one ~51k-token chat completion, 512 tokens, greedy.
|
||||||
Reports the engine's own `timings` (prefill, decode, draft acceptance).
|
Reports the engine's own `timings` (prefill, decode, draft acceptance).
|
||||||
The bench law applies: >=128 generated tokens, greedy, real text.
|
The bench law applies: >=128 generated tokens, greedy, real text.
|
||||||
@@ -17,7 +17,14 @@ Three probes, in increasing cost:
|
|||||||
resident at once, exact retrieval in every one of them.
|
resident at once, exact retrieval in every one of them.
|
||||||
C prefix-cache restore — probe A's cold prompt again, so the disk tier has
|
C prefix-cache restore — probe A's cold prompt again, so the disk tier has
|
||||||
to give the blocks back (cache_n > 0, TTFT collapses).
|
to give the blocks back (cache_n > 0, TTFT collapses).
|
||||||
|
D concurrency decode — `seqs` CONCURRENT 512-token generations at ~25 % of
|
||||||
|
the window. This is the cost a slot count imposes on DECODE, which no
|
||||||
|
prefill number shows: the fused-step schedule is unfair, so every stream is
|
||||||
|
printed plus the aggregate. Measured 2026-10-13 at 3 x 200,000 fp8:
|
||||||
|
single-stream 99.0 t/s (43.5k) and 93.3 (197k) — decode is nearly
|
||||||
|
window-free — against 3-stream 113.9/43.3/10.9 t/s = 18.4 t/s aggregate.
|
||||||
|
Concurrency, not the slab, is what decode pays for slots. The 2026-10-13
|
||||||
|
shape hunt missed this for a whole day because leg B generates 24 tokens.
|
||||||
PROBE LAW (learned the hard way, twice): radiance routes the thinking block to
|
PROBE LAW (learned the hard way, twice): radiance routes the thinking block to
|
||||||
`reasoning_content`, so a chat request whose budget is spent inside
|
`reasoning_content`, so a chat request whose budget is spent inside
|
||||||
`<think>` returns EMPTY `content` with `finish_reason: stop`. A probe that
|
`<think>` returns EMPTY `content` with `finish_reason: stop`. A probe that
|
||||||
@@ -168,6 +175,24 @@ def main():
|
|||||||
except Exception as e: # a preemption/timeout lands here
|
except Exception as e: # a preemption/timeout lands here
|
||||||
print(f"[B-{s}] FAILED after {time.time() - t0:.1f}s: {e!r}")
|
print(f"[B-{s}] FAILED after {time.time() - t0:.1f}s: {e!r}")
|
||||||
print(f"[B] total {time.time() - t0:.1f}s")
|
print(f"[B] total {time.time() - t0:.1f}s")
|
||||||
|
# D — concurrency decode: seqs streams, 512 tokens each, ~25 % depth.
|
||||||
|
dchars = int(0.25 * maxlen * 3.28)
|
||||||
|
dbodies = [chat(deep, dchars, f"D{i + 1}-9137", f"flint-marker-{i}", 512)
|
||||||
|
for i in range(seqs)]
|
||||||
|
print(f"[D] {seqs} concurrent streams x 512 tokens, "
|
||||||
|
f"{dchars:,} chars each")
|
||||||
|
t0 = time.time()
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=seqs) as ex:
|
||||||
|
futs = [ex.submit(post, b) for b in dbodies]
|
||||||
|
for i, fut in enumerate(futs, 1):
|
||||||
|
try:
|
||||||
|
j, wall, _ = fut.result()
|
||||||
|
show(f"D-s{i}", j, wall)
|
||||||
|
except Exception as e: # a preemption/timeout lands here
|
||||||
|
print(f"[D-s{i}] FAILED after {time.time() - t0:.1f}s: {e!r}")
|
||||||
|
tot = time.time() - t0
|
||||||
|
print(f"[D] {seqs} x 512 tokens in {tot:.1f}s = "
|
||||||
|
f"{seqs * 512 / tot:.1f} t/s aggregate decode")
|
||||||
j, wall, _ = post(chat(deep, 140_000, "A1-9137", "zephyr-lantern-7", 512))
|
j, wall, _ = post(chat(deep, 140_000, "A1-9137", "zephyr-lantern-7", 512))
|
||||||
show("C-prefix-hit", j, wall, "zephyr-lantern-7")
|
show("C-prefix-hit", j, wall, "zephyr-lantern-7")
|
||||||
|
|
||||||
|
|||||||
@@ -421,6 +421,36 @@ of **199,984 tokens** each (599,952 tokens) were accepted and completed on
|
|||||||
`/v1/completions`; a fourth full-height request is refused as "too large to ever
|
`/v1/completions`; a fourth full-height request is refused as "too large to ever
|
||||||
fit" — radiance never truncates.
|
fit" — radiance never truncates.
|
||||||
|
|
||||||
|
### The decode ladder (2026-10-13): slots are paid in concurrency, not prefill
|
||||||
|
|
||||||
|
Frank's challenge — "why are you not tracking decode?" — was right, and the
|
||||||
|
answer is a number now. 512 generated tokens (the bench law), greedy, cold
|
||||||
|
prompts, this shape (3 x 200,000, fp8, slab 25,600):
|
||||||
|
|
||||||
|
```
|
||||||
|
1-stream 43.5k: decode 99.0 t/s (prefill 4,042, accept 0.952)
|
||||||
|
1-stream 197k: decode 93.3 t/s (prefill 4,826, accept 0.938)
|
||||||
|
3-stream 43.5k: decode 113.9 / 43.3 / 10.9 t/s wall 83.4s
|
||||||
|
3-stream 197k: decode 88.9 / 16.3 / 64.6 t/s wall 122.4s
|
||||||
|
```
|
||||||
|
|
||||||
|
Two laws came out of it. **Decode is nearly window-free** — 99.0 at 43.5k,
|
||||||
|
93.3 at 197k, −6 % for 4.5x the depth — so a long conversation costs
|
||||||
|
prefill, not tokens-per-second. **Concurrency is where the slot count is
|
||||||
|
paid**: three simultaneous streams give 18.4 t/s aggregate at 43.5k and 12.5
|
||||||
|
at 197k against 99 single-stream, and the split is a lottery
|
||||||
|
(113.9/43.3/10.9), not a fair share — the fused-step schedule hands the step
|
||||||
|
to whoever it reached first, so one stream finishes at 113 t/s while its
|
||||||
|
sibling crawls at 10.9. That is what "3 slots" owes per token, and no prefill
|
||||||
|
number shows it.
|
||||||
|
|
||||||
|
Corpus caveat, stated at the claim: this probe's filler is a repetitive
|
||||||
|
ladder, so MTP acceptance is 0.93–0.97 against the 0.740 of the 2026-10-11
|
||||||
|
table below; these rows flatter decode relative to that table and are the
|
||||||
|
baseline for *this* corpus, not a replacement for those rows.
|
||||||
|
`probe-frank-archon-kv.py` now carries this leg as **D** (leg B generates 24
|
||||||
|
tokens, which is why a day of shape work priced only prefill).
|
||||||
|
|
||||||
### Recovery evidence
|
### Recovery evidence
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@@ -72,6 +72,26 @@
|
|||||||
raid6 array itself is healthy, 7/7; fstab has `nofail` so boot continued) —
|
raid6 array itself is healthy, 7/7; fstab has `nofail` so boot continued) —
|
||||||
media libraries on it read empty. `frank-job-digest.service` (frankbook
|
media libraries on it read empty. `frank-job-digest.service` (frankbook
|
||||||
job-hunt digest) is in `list-units --state=failed`.
|
job-hunt digest) is in `list-units --state=failed`.
|
||||||
|
- **The slab is a threshold, not a slope** — measured, same method (probe A
|
||||||
|
leg: 43,512 tokens, greedy, cold, disk prefix cache clean on every boot):
|
||||||
|
22,208 → 3,397 t/s, 24,000 → 3,290, **25,600 → 3,290**. The third step
|
||||||
|
bought nothing; the +22 % belongs to the 2026-10-11 arm at slab 26,071
|
||||||
|
(4,379 t/s), so the cliff is real and sits at ~26 GiB. The 2-slot arm that
|
||||||
|
would clear it (pool 3,072 + slab 27,897) remains untested — and the
|
||||||
|
paragraph above is amended: that arm's payoff is +22 % prefill at 2 slots,
|
||||||
|
not the +8.9 % the deployed pair ever showed (24,000 → 25,600 = 0 %).
|
||||||
|
- **Frank's decode challenge, answered with numbers**: 512 tokens, greedy,
|
||||||
|
cold — **decode 99.0 t/s single-stream at 43.5k and 93.3 at 197k** (decode
|
||||||
|
is nearly window-free: −6 % for 4.5× depth), while **3 concurrent streams
|
||||||
|
give 113.9/43.3/10.9 t/s = 18.4 t/s aggregate** at 43.5k and 12.5 at 197k.
|
||||||
|
The slot count is paid in decode concurrency — a fused-step lottery, not a
|
||||||
|
fair share — which is exactly the axis the shape hunt was blind to (probe
|
||||||
|
leg B generates 24 tokens). Corpus caveat at the claim: the ladder's filler
|
||||||
|
is repetitive, acceptance 0.93–0.97 vs the 0.740 of the 2026-10-11 decode
|
||||||
|
table, so these rows are the baseline for this corpus, not a replacement.
|
||||||
|
- **Seam:** `probe-frank-archon-kv.py` gains **leg D** (N-stream decode, 512
|
||||||
|
tokens, per-stream + aggregate) so no future shape change can be priced on
|
||||||
|
prefill alone.
|
||||||
|
|
||||||
|
|
||||||
## 2026-10-10
|
## 2026-10-10
|
||||||
|
|||||||
Reference in New Issue
Block a user