Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5934a6b47 | ||
|
|
40ad1f4a60 | ||
|
|
9de58ed6fd | ||
|
|
b9d21ae947 | ||
|
|
30e8ed55a0 |
No files matched your search
@@ -29,10 +29,10 @@
|
|||||||
# The scratch mirrors the production container contract exactly (serve-frank-
|
# The scratch mirrors the production container contract exactly (serve-frank-
|
||||||
# primary.sh): --network host, --init, seccomp=unconfined (io_uring for the
|
# primary.sh): --network host, --init, seccomp=unconfined (io_uring for the
|
||||||
# n-gram table), memlock unbounded (the ~132 GiB pinned ledger), /dev/kfd +
|
# n-gram table), memlock unbounded (the ~132 GiB pinned ledger), /dev/kfd +
|
||||||
# /dev/dri, the .rad ro, the state dir rw, the tune cache mount. The ONLY
|
# /dev/dri, the .rad ro, the tune cache mount. The ONLY differences: the
|
||||||
# differences: the container name (arbench, so prod's identity is untouched)
|
# container name (arbench, so prod's identity is untouched) and the prefix cache
|
||||||
# and a FRESH prefix-cache disk tier (arbench/, wiped per run) so the cold
|
# switched OFF (--prefix-cache-mib 0), so every prefill is cold — the tier is
|
||||||
# prefill is cold — the prod tier at kvcache/frank-archon is left intact.
|
# host RAM now, there is no per-run disk directory to wipe.
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
ENV_FILE="${1:-/home/dank/serverAppConfigs/scripts/frank-archon.env}"
|
ENV_FILE="${1:-/home/dank/serverAppConfigs/scripts/frank-archon.env}"
|
||||||
@@ -60,9 +60,8 @@ set -a; . "$ENV_FILE"; set +a
|
|||||||
sudo systemctl stop frank-archon >/dev/null 2>&1 || true
|
sudo systemctl stop frank-archon >/dev/null 2>&1 || true
|
||||||
podman rm -f "$SCRATCH" >/dev/null 2>&1 || true
|
podman rm -f "$SCRATCH" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
# --- fresh prefix-cache tier for a cold prefill (prod's tier untouched) ------
|
# --- the prefix cache is switched off below, so there is no scratch KV tree ---
|
||||||
FRESH_KV="$FRANK_ARCHON_STATE_DIR/kvcache/$SCRATCH"
|
# to wipe; the cold prefill comes from --prefix-cache-mib 0.
|
||||||
rm -rf "$FRESH_KV"; mkdir -p "$FRESH_KV"
|
|
||||||
mkdir -p "$FRANK_ARCHON_STATE_DIR/tune"
|
mkdir -p "$FRANK_ARCHON_STATE_DIR/tune"
|
||||||
|
|
||||||
# --- boot the scratch: the production run line, scratch name + fresh KV ------
|
# --- boot the scratch: the production run line, scratch name + fresh KV ------
|
||||||
@@ -73,7 +72,6 @@ podman run -d --name "$SCRATCH" \
|
|||||||
--ulimit memlock=-1:-1 \
|
--ulimit memlock=-1:-1 \
|
||||||
--device /dev/kfd --device /dev/dri \
|
--device /dev/kfd --device /dev/dri \
|
||||||
-v "$FRANK_ARCHON_MODEL_DIR":/models:ro \
|
-v "$FRANK_ARCHON_MODEL_DIR":/models:ro \
|
||||||
-v "$FRANK_ARCHON_STATE_DIR":/data \
|
|
||||||
-v "$FRANK_ARCHON_STATE_DIR/tune":/opt/radiance/share/radiance/tune \
|
-v "$FRANK_ARCHON_STATE_DIR/tune":/opt/radiance/share/radiance/tune \
|
||||||
-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro \
|
-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro \
|
||||||
"$FRANK_ARCHON_IMAGE" \
|
"$FRANK_ARCHON_IMAGE" \
|
||||||
@@ -87,12 +85,9 @@ podman run -d --name "$SCRATCH" \
|
|||||||
--placement "$FRANK_ARCHON_PLACEMENT" \
|
--placement "$FRANK_ARCHON_PLACEMENT" \
|
||||||
--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB" \
|
--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB" \
|
||||||
--gpu-headroom-mib "$FRANK_ARCHON_GPU_HEADROOM_MIB" \
|
--gpu-headroom-mib "$FRANK_ARCHON_GPU_HEADROOM_MIB" \
|
||||||
--vram-weights-mib "$FRANK_ARCHON_VRAM_WEIGHTS_MIB" \
|
|
||||||
--vram-kv-mib "$FRANK_ARCHON_VRAM_KV_MIB" \
|
|
||||||
--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE" \
|
--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE" \
|
||||||
--prefix-cache-host-mib "$FRANK_ARCHON_PREFIX_HOST_MIB" \
|
--prefix-cache-mib 0 \
|
||||||
--prefix-cache-dir "/data/kvcache/$SCRATCH" \
|
--busy-prefill-chunk "${FRANK_ARCHON_BUSY_PREFILL_CHUNK:-auto}" \
|
||||||
--prefix-cache-disk-mib "$FRANK_ARCHON_PREFIX_DISK_MIB" \
|
|
||||||
--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT" \
|
--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT" \
|
||||||
--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS" \
|
--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS" \
|
||||||
--max-num-batched-tokens "$FRANK_ARCHON_MAX_BATCHED_TOKENS" \
|
--max-num-batched-tokens "$FRANK_ARCHON_MAX_BATCHED_TOKENS" \
|
||||||
|
|||||||
+56
-25
@@ -7,10 +7,15 @@
|
|||||||
# only the reason a reader editing THIS line cannot recover from the page.
|
# only the reason a reader editing THIS line cannot recover from the page.
|
||||||
# Where the two disagree, this file wins on values; the boot ledger arbitrates
|
# Where the two disagree, this file wins on values; the boot ledger arbitrates
|
||||||
# the engine shape.
|
# the engine shape.
|
||||||
FRANK_ARCHON_IMAGE=stilldeadcode/radiance@sha256:4c3f484564bb2872784e46b0a59cbd71becc9c1e746e301a3596ffae253c322e
|
FRANK_ARCHON_IMAGE=stilldeadcode/radiance@sha256:d590e300234bf6d2f942a0b8d456d183153fd808f28820e6c2fa69c9389178ed
|
||||||
# 1.0.13 is pinned by digest on purpose: 1.2.0 is a DEAD END on this payload
|
# 1.8.1 (2026-10-18), pinned by digest. Two CLI breaks sit between it and the
|
||||||
# (acceptance 0.7123 vs 0.7549 — the page's Dead ends section names the suspect).
|
# 1.0.13 line this endpoint ran for two eras, and both are boot refusals, not
|
||||||
# The .rad file mounted under /models; /data holds the prefix-cache disk tier.
|
# warnings: --vram-weights-mib/--vram-kv-mib were REMOVED at 1.3.0 (the card is
|
||||||
|
# now split by the engine's budget resolver — see below), and the prefix cache
|
||||||
|
# lost its disk tier. Draft acceptance has to be re-scored on any pin past 1.2.0:
|
||||||
|
# 1.2.0's MoE weight rotation measured 0.7123 against the 0.7549 control, and the
|
||||||
|
# suspect is untangled (the page's Dead ends section names it).
|
||||||
|
# The .rad file mounts under /models; the tune cache mounts separately below.
|
||||||
# The model dir holds ONLY .rad files — the HF download and staging stay beside it.
|
# The model dir holds ONLY .rad files — the HF download and staging stay beside it.
|
||||||
FRANK_ARCHON_MODEL_DIR=/home/dank/models/rad
|
FRANK_ARCHON_MODEL_DIR=/home/dank/models/rad
|
||||||
FRANK_ARCHON_MODEL_FILE=qwen3.8-next-flash-fp8-iq4r-moe.rad
|
FRANK_ARCHON_MODEL_FILE=qwen3.8-next-flash-fp8-iq4r-moe.rad
|
||||||
@@ -52,21 +57,30 @@ FRANK_ARCHON_MAX_SEQS=3
|
|||||||
# sequence.
|
# sequence.
|
||||||
FRANK_ARCHON_MAX_MODEL_LEN=200000
|
FRANK_ARCHON_MAX_MODEL_LEN=200000
|
||||||
FRANK_ARCHON_PLACEMENT=expert_tiered
|
FRANK_ARCHON_PLACEMENT=expert_tiered
|
||||||
# Pinned host pool for expert rows that do not fit VRAM. It moves WITH
|
# Pinned host pool for expert rows that do not fit VRAM. Under the budget
|
||||||
# VRAM_WEIGHTS: the pair and this pool serve the per-rank resident set together,
|
# resolver this is ALSO the lever that decides which experts stay on the card:
|
||||||
# so cutting the slab spills here — under-sizing it is a boot failure (36,864
|
# the card's leftover goes to the expert plane first and the KV cache takes the
|
||||||
|
# rest, so growing the pool moves experts off the card and shrinking it spills
|
||||||
|
# them onto VRAM the cache wanted. Under-sizing it is a boot failure (36,864
|
||||||
# refused a boot). The ledger's coverage line is the referee, not this file.
|
# refused a boot). The ledger's coverage line is the referee, not this file.
|
||||||
FRANK_ARCHON_HOST_POOL_MIB=44928
|
# Sized so the cache clears the 3 x MAX_MODEL_LEN contract: the 1.8.1 boot at
|
||||||
|
# 44,928 resolved the cache to 556,348 tokens — 2.8 sessions — and three
|
||||||
|
# concurrent full-height requests came back 400 in 0.0 s. Tokens scale with the
|
||||||
|
# GiB the cache wins, so +640 MiB a rank buys ~44,000 tokens of ceiling with
|
||||||
|
# ~2.5% off the expert slab.
|
||||||
|
FRANK_ARCHON_HOST_POOL_MIB=45568
|
||||||
# VRAM left unclaimed per card (publisher default 96 MiB); the engine's settle
|
# VRAM left unclaimed per card (publisher default 96 MiB); the engine's settle
|
||||||
# floor is built from it.
|
# floor is built from it.
|
||||||
FRANK_ARCHON_GPU_HEADROOM_MIB=96
|
FRANK_ARCHON_GPU_HEADROOM_MIB=96
|
||||||
# ONE budget per card: VRAM_WEIGHTS + VRAM_KV <= 30,969 MiB, the ceiling the
|
# There is no VRAM pair any more. --vram-weights-mib/--vram-kv-mib were removed
|
||||||
# engine's own budget table prints (derivation and the slab/pool price: the
|
# at 1.3.0: the engine takes capacity - already-held - GPU_HEADROOM - arena,
|
||||||
# page's VRAM laws). Idle KV VRAM is ALSO the expert cache's spillover, so a
|
# puts the static (non-expert) weights off the top, then divides the rest between
|
||||||
# bigger pool pays twice — which is why the pool sits at the contract and the
|
# the expert plane and the KV cache — experts first when the cache has no idle
|
||||||
# slab takes the rest.
|
# blocks to lend, and never less than ONE MAX_MODEL_LEN sequence for the cache.
|
||||||
FRANK_ARCHON_VRAM_WEIGHTS_MIB=25600
|
# What moves the split from here is HOST_POOL_MIB (which experts stay resident),
|
||||||
FRANK_ARCHON_VRAM_KV_MIB=5120
|
# MAX_MODEL_LEN/MAX_SEQS (the cache bound) and GPU_HEADROOM_MIB. The slab size
|
||||||
|
# the prefill-slope law cares about is a boot-ledger line now, not a knob: read
|
||||||
|
# it after every resize instead of asserting it here.
|
||||||
# fp8 is the ONLY rung below bf16 on this engine: one kv_dtype for the whole
|
# fp8 is the ONLY rung below bf16 on this engine: one kv_dtype for the whole
|
||||||
# cache, so llama.cpp's exact-K/quantized-V split (frank-zealot) is unservable
|
# cache, so llama.cpp's exact-K/quantized-V split (frank-zealot) is unservable
|
||||||
# here. bf16 costs 1.89x fp8, not 2x — the QSA block-key plane is dtype-fixed.
|
# here. bf16 costs 1.89x fp8, not 2x — the QSA block-key plane is dtype-fixed.
|
||||||
@@ -75,20 +89,37 @@ FRANK_ARCHON_KV_DTYPE=fp8
|
|||||||
# 2, and 3 x (1+2) = 9 rows stays inside the wht6 25-row exactness bound.
|
# 2, and 3 x (1+2) = 9 rows stays inside the wht6 25-row exactness bound.
|
||||||
FRANK_ARCHON_SPEC_TOKENS=2
|
FRANK_ARCHON_SPEC_TOKENS=2
|
||||||
FRANK_ARCHON_MAX_BATCHED_TOKENS=2048
|
FRANK_ARCHON_MAX_BATCHED_TOKENS=2048
|
||||||
# Prefix cache tiers. The host tier is sized in ENTRIES and one entry tracks the
|
# Step sharing. A prefill chunk that shares a step with decoding sequences holds
|
||||||
# cache dtype (58.50 KiB at fp8), so a dtype change re-sizes the parked set
|
# the device for the chunk's whole time, and every decode row in that step waits
|
||||||
# without touching these numbers.
|
# that long for its next token (the census: [[LLM Performance Diagnosis]] §9).
|
||||||
FRANK_ARCHON_PREFIX_HOST_MIB=8192
|
# `auto` leaves each decode row behind the chunk a row plus its draft window and
|
||||||
FRANK_ARCHON_PREFIX_DISK_MIB=65536
|
# keeps a share for whatever is waiting to be admitted; a number pins the chunk's
|
||||||
|
# cap; `off` is the pre-1.4 behaviour this endpoint ran for two eras, where the
|
||||||
|
# chunk took the step and admission never ran. Interleave inserts N decode-only
|
||||||
|
# steps after a chunk step taken beside decoders: it protects their cadence and
|
||||||
|
# holds a waiting request out of those steps, so it stays 0 until the post-migration
|
||||||
|
# decode-vs-prefill buckets say it is wanted.
|
||||||
|
FRANK_ARCHON_BUSY_PREFILL_CHUNK=auto
|
||||||
|
FRANK_ARCHON_PREFILL_INTERLEAVE=0
|
||||||
|
# Prefix cache: pinned host memory only. The disk tier was removed outright
|
||||||
|
# (--prefix-cache-dir and --prefix-cache-disk-mib are refusals), so what used to
|
||||||
|
# be restored from NVMe is now re-prefilled. The tier is sized in ENTRIES and one
|
||||||
|
# entry tracks the cache dtype (58.50 KiB at fp8). Watch prefix_hit_rate after
|
||||||
|
# this change: a drop is extra prefill, and prefill is exactly the traffic that
|
||||||
|
# costs decode its cadence.
|
||||||
|
FRANK_ARCHON_PREFIX_CACHE_MIB=8192
|
||||||
# Frank's pin law: the PLE n-gram table serves from pinned host RAM the cards
|
# Frank's pin law: the PLE n-gram table serves from pinned host RAM the cards
|
||||||
# read. `ram` REFUSES the start if memlock is too small — the unit's
|
# read. `ram` REFUSES the start if memlock is too small — the unit's
|
||||||
# LimitMEMLOCK=infinity is the other half of this law.
|
# LimitMEMLOCK=infinity is the other half of this law.
|
||||||
FRANK_ARCHON_NGRAM_PLACEMENT=ram
|
FRANK_ARCHON_NGRAM_PLACEMENT=ram
|
||||||
# TTM preflight. The pinned ledger (~147 GiB) rides TTM's shared pages, and the
|
# TTM preflight. The pinned ledger rides TTM's shared pages, and the kernel
|
||||||
# kernel RESETS pages_limit to half of RAM on every boot; below the plan the
|
# RESETS pages_limit to half of RAM on every boot; below the plan the load dies
|
||||||
# load dies mid-pin with an anonymous allocator error. ttm-preflight.sh raises
|
# mid-pin with an anonymous allocator error. ttm-preflight.sh raises the knob
|
||||||
# the knob itself before refusing by name, so recovery is a boot, not a visit.
|
# itself before refusing by name, so recovery is a boot, not a visit.
|
||||||
FRANK_ARCHON_TTM_MIN_MIB=150000
|
# Floor = 2 x HOST_POOL + 48,824 (static weights + arena) + PREFIX_CACHE + MNBT
|
||||||
|
# per the bats ledger test; at the 45,568 pool that computes to 150,200 MiB, so
|
||||||
|
# the floor sits just above it.
|
||||||
|
FRANK_ARCHON_TTM_MIN_MIB=152000
|
||||||
FRANK_ARCHON_TTM_TARGET_MIB=204800
|
FRANK_ARCHON_TTM_TARGET_MIB=204800
|
||||||
# Escape hatch for experiments. Unset -> no extra argv; the serve script expands
|
# Escape hatch for experiments. Unset -> no extra argv; the serve script expands
|
||||||
# this unquoted on purpose, so keep multi-flag values as one string.
|
# this unquoted on purpose, so keep multi-flag values as one string.
|
||||||
|
|||||||
@@ -32,9 +32,12 @@ PARALLEL=3
|
|||||||
# on [[frank-zealot]]); 1024×6 keeps it a clean multiple of the ubatch.
|
# on [[frank-zealot]]); 1024×6 keeps it a clean multiple of the ubatch.
|
||||||
BATCH_SIZE=6144
|
BATCH_SIZE=6144
|
||||||
# Ubatch is a prefill knob (decode never moves with it) and it sets the
|
# Ubatch is a prefill knob (decode never moves with it) and it sets the
|
||||||
# compute-buffer size — which is what decides whether a drafter fits: 1024
|
# compute-buffer size, which decides whether a drafter fits. 1024 is the rung
|
||||||
# hands back ~1,306 MiB beside the draft context, and it is the rung the
|
# every measured MTP arm here ran on (213.5 t/s against 109.2 at 2048). Its
|
||||||
# measured MTP arm ran (213.5 t/s at 1024 against 109.2 at 2048).
|
# VRAM credit is SHAPE-specific: the 786,432-pool arm census showed ~1,306 MiB
|
||||||
|
# back, this boot measured 2,089.88 MiB of target compute against 2,496.13 at
|
||||||
|
# ubatch 2048 — 406 MiB back, with the split moving (CUDA0 +257, CUDA_Host
|
||||||
|
# −663). The drafter is funded by CACHE_TYPE_V below, not by this knob.
|
||||||
UBATCH_SIZE=1024
|
UBATCH_SIZE=1024
|
||||||
# K exact, V in the 8-bit class: 16,384 + 8,704 = 25,088 B/token (8,192
|
# K exact, V in the 8-bit class: 16,384 + 8,704 = 25,088 B/token (8,192
|
||||||
# elements per token per cache × 2 B for f16, × 1.0625 for q8_0 — there is no
|
# elements per token per cache × 2 B for f16, × 1.0625 for q8_0 — there is no
|
||||||
|
|||||||
@@ -15,12 +15,13 @@
|
|||||||
# log states every budget before anything is allocated (weights vs KV
|
# log states every budget before anything is allocated (weights vs KV
|
||||||
# split, the expert host pool's coverage of the worst case, the PLE pin,
|
# split, the expert host pool's coverage of the worst case, the PLE pin,
|
||||||
# the P2P answer per pair) — read it after every resize.
|
# the P2P answer per pair) — read it after every resize.
|
||||||
# Deployed shape (2026-10-13): THREE decode slots x 200,000 tokens, fp8
|
# Deployed shape (2026-10-19, radiance 1.8.1): THREE decode slots x 200,000
|
||||||
# (quantized) KV in a 5,120 MiB pool (contract 3 x 200,000 + 1.3 %) and a
|
# tokens, fp8 KV, 44 GiB/rank pinned expert pool, MTP depth 2, prefix cache in
|
||||||
# 25,600 MiB resident expert slab — 30,720 MiB of the 30,969 MiB the engine's
|
# pinned host RAM, PLE pinned in RAM. The per-card split between the expert slab
|
||||||
# own budget table makes claimable, spent on the slab because prefill is
|
# and the KV pool is NO LONGER an operator number — 1.3.0 removed the VRAM pair
|
||||||
# slab-limited. 44 GiB/rank pinned expert pool, MTP depth 2, prefix cache host
|
# and the budget resolver derives it from headroom, the cache bound and the host
|
||||||
# 8 GiB + disk 64 GiB, PLE pinned in RAM.
|
# pool, so the slab size and the pool's token count are LEDGER lines: after every
|
||||||
|
# boot read them out of the log and check the pool still backs 3 x 200,000.
|
||||||
#
|
#
|
||||||
# The root unit (scripts/frank-archon.service, User=dank,
|
# The root unit (scripts/frank-archon.service, User=dank,
|
||||||
# LimitMEMLOCK=infinity) grants the pin budget: 2 x 44 GiB expert pools +
|
# LimitMEMLOCK=infinity) grants the pin budget: 2 x 44 GiB expert pools +
|
||||||
@@ -56,13 +57,11 @@ set +a
|
|||||||
: "${FRANK_ARCHON_PLACEMENT:?FRANK_ARCHON_PLACEMENT must be set}"
|
: "${FRANK_ARCHON_PLACEMENT:?FRANK_ARCHON_PLACEMENT must be set}"
|
||||||
: "${FRANK_ARCHON_HOST_POOL_MIB:?FRANK_ARCHON_HOST_POOL_MIB must be set}"
|
: "${FRANK_ARCHON_HOST_POOL_MIB:?FRANK_ARCHON_HOST_POOL_MIB must be set}"
|
||||||
: "${FRANK_ARCHON_GPU_HEADROOM_MIB:?FRANK_ARCHON_GPU_HEADROOM_MIB must be set}"
|
: "${FRANK_ARCHON_GPU_HEADROOM_MIB:?FRANK_ARCHON_GPU_HEADROOM_MIB must be set}"
|
||||||
: "${FRANK_ARCHON_VRAM_WEIGHTS_MIB:?FRANK_ARCHON_VRAM_WEIGHTS_MIB must be set}"
|
: "${FRANK_ARCHON_BUSY_PREFILL_CHUNK:?FRANK_ARCHON_BUSY_PREFILL_CHUNK must be set (auto|off|N)}"
|
||||||
: "${FRANK_ARCHON_VRAM_KV_MIB:?FRANK_ARCHON_VRAM_KV_MIB must be set}"
|
|
||||||
: "${FRANK_ARCHON_KV_DTYPE:?FRANK_ARCHON_KV_DTYPE must be set}"
|
: "${FRANK_ARCHON_KV_DTYPE:?FRANK_ARCHON_KV_DTYPE must be set}"
|
||||||
: "${FRANK_ARCHON_SPEC_TOKENS:?FRANK_ARCHON_SPEC_TOKENS must be set}"
|
: "${FRANK_ARCHON_SPEC_TOKENS:?FRANK_ARCHON_SPEC_TOKENS must be set}"
|
||||||
: "${FRANK_ARCHON_MAX_BATCHED_TOKENS:?FRANK_ARCHON_MAX_BATCHED_TOKENS must be set}"
|
: "${FRANK_ARCHON_MAX_BATCHED_TOKENS:?FRANK_ARCHON_MAX_BATCHED_TOKENS must be set}"
|
||||||
: "${FRANK_ARCHON_PREFIX_HOST_MIB:?FRANK_ARCHON_PREFIX_HOST_MIB must be set}"
|
: "${FRANK_ARCHON_PREFIX_CACHE_MIB:?FRANK_ARCHON_PREFIX_CACHE_MIB must be set}"
|
||||||
: "${FRANK_ARCHON_PREFIX_DISK_MIB:?FRANK_ARCHON_PREFIX_DISK_MIB must be set}"
|
|
||||||
: "${FRANK_ARCHON_NGRAM_PLACEMENT:?FRANK_ARCHON_NGRAM_PLACEMENT must be set}"
|
: "${FRANK_ARCHON_NGRAM_PLACEMENT:?FRANK_ARCHON_NGRAM_PLACEMENT must be set}"
|
||||||
: "${FRANK_ARCHON_TTM_MIN_MIB:?FRANK_ARCHON_TTM_MIN_MIB must be set}"
|
: "${FRANK_ARCHON_TTM_MIN_MIB:?FRANK_ARCHON_TTM_MIN_MIB must be set}"
|
||||||
: "${FRANK_ARCHON_TTM_TARGET_MIB:?FRANK_ARCHON_TTM_TARGET_MIB must be set}"
|
: "${FRANK_ARCHON_TTM_TARGET_MIB:?FRANK_ARCHON_TTM_TARGET_MIB must be set}"
|
||||||
@@ -103,19 +102,12 @@ if [ ! -f "$FRANK_ARCHON_TEMPLATE" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$FRANK_ARCHON_STATE_DIR/kvcache/frank-archon"
|
|
||||||
# The engine's create is NOT recursive: with only the state dir mounted, its
|
|
||||||
# "cannot create /data/kvcache/frank-archon: No such file or directory"
|
|
||||||
# left the SSD prefix tier off (measured 2026-10-06 boot ledger). Pre-create
|
|
||||||
# the full path on the host so the tier opens on first boot.
|
|
||||||
|
|
||||||
mkdir -p "$FRANK_ARCHON_STATE_DIR/tune"
|
mkdir -p "$FRANK_ARCHON_STATE_DIR/tune"
|
||||||
# rad-tune's kernel-selection cache (see the runbook's "Tuning levers"):
|
# rad-tune's kernel-selection cache (see the runbook's "Tuning levers"):
|
||||||
# the engine's selector reads $RADIANCE_HOME/tune/<machine>.tune at boot;
|
# the engine's selector reads $RADIANCE_HOME/tune/<machine>.tune at boot;
|
||||||
# $RADIANCE_HOME defaults to /opt/radiance, which lives in the image, so
|
# $RADIANCE_HOME defaults to /opt/radiance, which lives in the image, so
|
||||||
# the cache must ride a host mount or it dies with the --rm container
|
# the cache must ride a host mount or it dies with the --rm container
|
||||||
# that wrote it. The dir is pre-created for the same reason as kvcache
|
# that wrote it. The engine's create is not recursive, so the dir is pre-created.
|
||||||
# (the engine's create is not recursive).
|
|
||||||
|
|
||||||
if [ ! -e /dev/kfd ] || [ ! -d /dev/dri ]; then
|
if [ ! -e /dev/kfd ] || [ ! -d /dev/dri ]; then
|
||||||
echo "ERROR: GPU device nodes absent (/dev/kfd, /dev/dri)" >&2
|
echo "ERROR: GPU device nodes absent (/dev/kfd, /dev/dri)" >&2
|
||||||
@@ -148,6 +140,15 @@ done
|
|||||||
LOG=/home/dank/logs/frank_archon.log
|
LOG=/home/dank/logs/frank_archon.log
|
||||||
mkdir -p "$(dirname "$LOG")"
|
mkdir -p "$(dirname "$LOG")"
|
||||||
|
|
||||||
|
# Interleave is opt-in: 0 is the engine's default and passing it anyway would put
|
||||||
|
# a flag in argv that changes nothing but the record. The sharing cap is always
|
||||||
|
# explicit because `auto` vs `off` is the difference between decode waiting one
|
||||||
|
# chunk and waiting the whole step.
|
||||||
|
PREFILL_ARGS=()
|
||||||
|
if [ "${FRANK_ARCHON_PREFILL_INTERLEAVE:-0}" -gt 0 ]; then
|
||||||
|
PREFILL_ARGS=(--prefill-interleave "$FRANK_ARCHON_PREFILL_INTERLEAVE")
|
||||||
|
fi
|
||||||
|
|
||||||
# Publisher-vetted container contract (docs/DOCKER.md, compose/common.yaml):
|
# Publisher-vetted container contract (docs/DOCKER.md, compose/common.yaml):
|
||||||
# --network host (the server binds the host's addresses directly, no NAT),
|
# --network host (the server binds the host's addresses directly, no NAT),
|
||||||
# --init (the engine releases the cards on SIGTERM), seccomp=unconfined
|
# --init (the engine releases the cards on SIGTERM), seccomp=unconfined
|
||||||
@@ -156,8 +157,9 @@ mkdir -p "$(dirname "$LOG")"
|
|||||||
# makes for host memory), memlock unbounded (the pinned ledger — legal
|
# makes for host memory), memlock unbounded (the pinned ledger — legal
|
||||||
# because the root unit grants LimitMEMLOCK=infinity to this dank process),
|
# because the root unit grants LimitMEMLOCK=infinity to this dank process),
|
||||||
# /dev/kfd + /dev/dri (render/video groups are moot for a root container).
|
# /dev/kfd + /dev/dri (render/video groups are moot for a root container).
|
||||||
# The template rides a single-file mount; the .rad dir is ro; /data holds
|
# The template rides a single-file mount and the .rad dir is ro. The prefix cache
|
||||||
# the prefix-cache disk tier.
|
# has no disk tier any more, so the only host state this container writes is the
|
||||||
|
# rad-tune cache under /opt/radiance/share/radiance/tune.
|
||||||
podman run -d --name "$FRANK_ARCHON_CONTAINER" \
|
podman run -d --name "$FRANK_ARCHON_CONTAINER" \
|
||||||
--network host \
|
--network host \
|
||||||
--init \
|
--init \
|
||||||
@@ -165,7 +167,6 @@ podman run -d --name "$FRANK_ARCHON_CONTAINER" \
|
|||||||
--ulimit memlock=-1:-1 \
|
--ulimit memlock=-1:-1 \
|
||||||
--device /dev/kfd --device /dev/dri \
|
--device /dev/kfd --device /dev/dri \
|
||||||
-v "$FRANK_ARCHON_MODEL_DIR":/models:ro \
|
-v "$FRANK_ARCHON_MODEL_DIR":/models:ro \
|
||||||
-v "$FRANK_ARCHON_STATE_DIR":/data \
|
|
||||||
-v "$FRANK_ARCHON_STATE_DIR/tune":/opt/radiance/share/radiance/tune \
|
-v "$FRANK_ARCHON_STATE_DIR/tune":/opt/radiance/share/radiance/tune \
|
||||||
-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro \
|
-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro \
|
||||||
"$FRANK_ARCHON_IMAGE" \
|
"$FRANK_ARCHON_IMAGE" \
|
||||||
@@ -179,15 +180,13 @@ podman run -d --name "$FRANK_ARCHON_CONTAINER" \
|
|||||||
--placement "$FRANK_ARCHON_PLACEMENT" \
|
--placement "$FRANK_ARCHON_PLACEMENT" \
|
||||||
--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB" \
|
--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB" \
|
||||||
--gpu-headroom-mib "$FRANK_ARCHON_GPU_HEADROOM_MIB" \
|
--gpu-headroom-mib "$FRANK_ARCHON_GPU_HEADROOM_MIB" \
|
||||||
--vram-weights-mib "$FRANK_ARCHON_VRAM_WEIGHTS_MIB" \
|
|
||||||
--vram-kv-mib "$FRANK_ARCHON_VRAM_KV_MIB" \
|
|
||||||
--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE" \
|
--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE" \
|
||||||
--prefix-cache-host-mib "$FRANK_ARCHON_PREFIX_HOST_MIB" \
|
--prefix-cache-mib "$FRANK_ARCHON_PREFIX_CACHE_MIB" \
|
||||||
--prefix-cache-dir /data/kvcache/frank-archon \
|
|
||||||
--prefix-cache-disk-mib "$FRANK_ARCHON_PREFIX_DISK_MIB" \
|
|
||||||
--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT" \
|
--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT" \
|
||||||
--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS" \
|
--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS" \
|
||||||
--max-num-batched-tokens "$FRANK_ARCHON_MAX_BATCHED_TOKENS" \
|
--max-num-batched-tokens "$FRANK_ARCHON_MAX_BATCHED_TOKENS" \
|
||||||
|
--busy-prefill-chunk "$FRANK_ARCHON_BUSY_PREFILL_CHUNK" \
|
||||||
|
"${PREFILL_ARGS[@]}" \
|
||||||
${FRANK_ARCHON_EXTRA_ARGS:+$FRANK_ARCHON_EXTRA_ARGS} \
|
${FRANK_ARCHON_EXTRA_ARGS:+$FRANK_ARCHON_EXTRA_ARGS} \
|
||||||
> "$LOG" 2>&1
|
> "$LOG" 2>&1
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,12 @@
|
|||||||
# accepts well (0.798/0.617 per position, mean length 2.41, measured 2026-10-18);
|
# accepts well (0.798/0.617 per position, mean length 2.41, measured 2026-10-18);
|
||||||
# what made it lose that evening was the bill, not the drafts — the draft context
|
# what made it lose that evening was the bill, not the drafts — the draft context
|
||||||
# is built against the target's WHOLE pool, so blk.32 adds 4,096 B/position
|
# is built against the target's WHOLE pool, so blk.32 adds 4,096 B/position
|
||||||
# (2,352.00 MiB at 602,112) plus ~0.45 GiB of buffers at this ubatch, and the
|
# (2,352.00 MiB at 602,112) plus 480.97 MiB of its own compute buffers on the
|
||||||
# recurrent state triples. Dropping V to q8_0 (−3,840 MiB at this pool) and the
|
# card, and it triples the recurrent state per slot (452.25 MiB for three cells
|
||||||
# ubatch to 1024 (−~1,306 MiB of compute buffers) is how those two bills got
|
# against 50.25 a cell with the drafter off). CACHE_TYPE_V=q8_0 is what pays
|
||||||
# paid; the arm census and the rates are on [[frank-zealot]]. SPEC_TYPE=none is
|
# that: 7,680 B/token cheaper than exact V, 4,410 MiB at this pool. The ubatch
|
||||||
|
# drop to 1024 contributes ~406 MiB here, NOT the ~1,306 the 786,432-pool census
|
||||||
|
# showed — that figure does not transfer between shapes. SPEC_TYPE=none is
|
||||||
# the rollback and strips the whole flag set.
|
# the rollback and strips the whole flag set.
|
||||||
#
|
#
|
||||||
# Sampling: the checkpoint carries the publisher's thinking recipe as GGUF
|
# Sampling: the checkpoint carries the publisher's thinking recipe as GGUF
|
||||||
@@ -81,8 +83,8 @@ fi
|
|||||||
# Compute-buffer geometry. Ubatch is a prefill knob (decode never moves).
|
# Compute-buffer geometry. Ubatch is a prefill knob (decode never moves).
|
||||||
# The logical batch is VRAM- and throughput-neutral at a fixed ubatch, so 6144
|
# The logical batch is VRAM- and throughput-neutral at a fixed ubatch, so 6144
|
||||||
# (1024×6) is free; the ubatch is what sets the compute-buffer size, and 1024 is
|
# (1024×6) is free; the ubatch is what sets the compute-buffer size, and 1024 is
|
||||||
# the rung that leaves room for the draft context (−~1,306 MiB against 2048, and
|
# the rung every measured MTP arm here ran on (213.5 t/s at 1024 against 109.2
|
||||||
# the measured MTP arm ran here: 213.5 t/s at 1024 against 109.2 at 2048).
|
# at 2048) — worth ~406 MiB at THIS shape, not the ~1,306 the old pool showed.
|
||||||
: "${BATCH_SIZE:=6144}"
|
: "${BATCH_SIZE:=6144}"
|
||||||
: "${UBATCH_SIZE:=1024}"
|
: "${UBATCH_SIZE:=1024}"
|
||||||
# Asymmetric KV: f16 K (the engine's own default, spelled out so the contract is
|
# Asymmetric KV: f16 K (the engine's own default, spelled out so the contract is
|
||||||
|
|||||||
@@ -47,11 +47,12 @@ buys both and costs the keys their precision.
|
|||||||
**MTP is ON (Frank, 2026-10-19).** The drafter was always good — 2026-10-18 measured acceptance 0.798 / 0.617 per
|
**MTP is ON (Frank, 2026-10-19).** The drafter was always good — 2026-10-18 measured acceptance 0.798 / 0.617 per
|
||||||
position, mean accepted length 2.41, and the publisher's card says depth 2 works best — and arming it is a
|
position, mean accepted length 2.41, and the publisher's card says depth 2 works best — and arming it is a
|
||||||
budget decision, not a flag: the draft context is built against the *target's* pool, so `blk.32` bills 4,096
|
budget decision, not a flag: the draft context is built against the *target's* pool, so `blk.32` bills 4,096
|
||||||
B/position (2,352.00 MiB at 602,112) plus ~0.45 GiB of buffers at this ubatch and its own recurrent cells.
|
B/position (2,352.00 MiB at 602,112) plus 480.97 MiB of its own CUDA0 buffers, and it triples the recurrent
|
||||||
`CACHE_TYPE_V=q8_0` (−3,840 MiB against exact V at this pool) and `UBATCH_SIZE=1024` (−~1,306 MiB of compute
|
state (452.25 MiB for three cells against 150.75 with the drafter off). `CACHE_TYPE_V=q8_0` is what pays that:
|
||||||
buffers, and the rung every measured MTP arm here ran on) are what pay for it; `UBATCH_SIZE=2048` beside an armed
|
7,680 B/token cheaper than exact V = **4,410.00 MiB** at this pool. `UBATCH_SIZE=1024` — the rung every measured
|
||||||
drafter is the shape that halved decode (167.2 → 109.2 t/s). `--spec-draft-type-k`/`--spec-draft-type-v` (default
|
MTP arm here ran on — contributes only ~406 MiB at THIS shape, not the ~1,306 the 786,432-pool census showed,
|
||||||
f16, verified in this build's `--help`) would cut the draft's bill again and stay at their default; there is no
|
and `UBATCH_SIZE=2048` beside an armed drafter is still the shape that halved decode (167.2 → 109.2 t/s).
|
||||||
|
`--spec-draft-type-k`/`--spec-draft-type-v` (default f16, verified in this build's `--help`) would cut the draft's bill again and stay at their default; there is no
|
||||||
`--spec-draft-model` — the draft rides the main model's weights, so a draft file would load the trunk twice.
|
`--spec-draft-model` — the draft rides the main model's weights, so a draft file would load the trunk twice.
|
||||||
`SPEC_TYPE=none` is the rollback and strips the whole set.
|
`SPEC_TYPE=none` is the rollback and strips the whole set.
|
||||||
|
|
||||||
@@ -62,23 +63,47 @@ longer prompt with a 400, never a truncation — plus `maxTokens: 16384`, `input
|
|||||||
only `xhigh|medium|low` and raises on anything else), `extraBody` 1.0 / 0.95 / 20 / `min_p 0`, and the
|
only `xhigh|medium|low` and raises on anything else), `extraBody` 1.0 / 0.95 / 20 / `min_p 0`, and the
|
||||||
`compactionModel` of [[frank-archon]], [[frank-dragoon]] **and** frank-zealot all pointing here.
|
`compactionModel` of [[frank-archon]], [[frank-dragoon]] **and** frank-zealot all pointing here.
|
||||||
|
|
||||||
**This shape ships unbenchmarked, by law.** Frank ordered the reslice, not a
|
**No rates, by law.** Frank ordered the reslice, not a number: the evidence a swap needs is
|
||||||
number, so the evidence a swap needs is the seam's fit gate (it prices cache +
|
the seam's fit gate, the deployer's health gate, and the boot ledger below. The previous era's
|
||||||
draft cache + recurrent states against the 24,123 MiB the driver leaves
|
exact-KV boot and its rate floors live in that era's row; those floors were measured while
|
||||||
addressable, and refuses the two boots this shape can walk into: exact V with the
|
another consumer drove the other slot (56 prompts in three minutes, 96 % GPU-util), the exact
|
||||||
drafter armed, and the retired dtype pair at the retired pool), the deployer's
|
condition a bench window exists to exclude.
|
||||||
health gate, and the first verbosity-4 ledger of the new dtype pair — which is
|
|
||||||
recorded on this page because projections drift, and nowhere else. The previous
|
**The 2026-10-19 boot, measured** — verbosity-4 ledger of `ba69ea5`, started 03:21:56 PDT.
|
||||||
era's exact-KV boot and its rate floors live in that era's row below; those floors
|
Recorded here because projections drift, and nowhere else:
|
||||||
were measured while another consumer drove the other slot (56 prompts in three
|
|
||||||
minutes, 96 % GPU-util), the exact condition a bench window exists to exclude.
|
| Term | Ledger |
|
||||||
|
|---|---|
|
||||||
|
| Target KV over the 602,112 pool | **14,406.00 MiB** — K (f16) 9,408.00 + V (q8_0) 4,998.00, `200704 cells, 8 layers, 3/3 seqs` |
|
||||||
|
| Draft KV (`blk.32`, its own f16 context) | **2,352.00 MiB** — 1,176.00 + 1,176.00, `200704 cells, 1 layers, 3/3 seqs`: the whole pool, again |
|
||||||
|
| Recurrent state | **452.25 MiB** — `3 cells, 32 layers, 3 seqs, 2 rs_seq`, R (f32) 20.25 + S (f32) 432.00 |
|
||||||
|
| Compute buffers | target 1,665.00 CUDA0 + 424.88 CUDA_Host; draft context 480.97 + 424.86 |
|
||||||
|
| Weights | 2,283.29 CUDA0 + 257.66 CPU-mapped |
|
||||||
|
| Projector | 595.29 model + 248.10 compute + 24.93 CPU (its 868.32 worst case is still charged AFTER the engine's fit check) |
|
||||||
|
| Engine's own verdict | projected 21,639 vs 23,404 free, then **"cannot meet free memory target of 1,867 MiB, need to reduce device memory by 102 MiB"** |
|
||||||
|
| Settled | **22,870 used / 1,255 free**, `n_slots = 3`, `n_ctx_slot = 200704`, `kv_unified = false` |
|
||||||
|
|
||||||
|
This is the first boot on this card that does **not** meet llama.cpp's own free-memory target,
|
||||||
|
and 1,255 MiB settled sits under the ~2 GiB band every previous era held. It boots, `/health`
|
||||||
|
answers, and the seam's gate still passes — it priced 22,428 MiB, conservative by 442 against
|
||||||
|
this ledger. The cheapest rungs back into the band are `CTX_SIZE=401408` (two conversations) or
|
||||||
|
`SPEC_TYPE=none`; both are one line and neither changes the payload.
|
||||||
|
|
||||||
|
**The drafter is engaged, measured on the same boot** (three ordinary requests, not a bench):
|
||||||
|
acceptance 0.706 and 0.763 accepted-per-generated, mean accepted length 2.41 / 2.53,
|
||||||
|
per-position rates (0.882, 0.765) and (0.871, 0.699) — depth 2 earning its keep at 0.3–1.5 MiB
|
||||||
|
of draft state per saved prompt. The three probes that prove a swap: chat → `"zealot alive"`
|
||||||
|
with 448 completion tokens (at `max_tokens: 64` the same request returns EMPTY content with
|
||||||
|
`finish_reason: length` — the thinking-budget trap, not a fault); tools →
|
||||||
|
`finish_reason: tool_calls` with `{"a":24,"b":7}`; vision → a 512 px solid-red PNG answers
|
||||||
|
"Red" at `prompt_tokens` 280.
|
||||||
|
|
||||||
**Fallback rungs**, cheapest first — one line of `frank-zealot.env` each, and each must keep the seam's fit gate green:
|
**Fallback rungs**, cheapest first — one line of `frank-zealot.env` each, and each must keep the seam's fit gate green:
|
||||||
|
|
||||||
| Knob | Effect from the shipped shape |
|
| Knob | Effect from the shipped shape |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `SPEC_TYPE=none` | the drafter off: hands back 2,352 MiB of draft cache plus its buffers and recurrent cells, at the cost of the ~+28 % decode the 2026-10-18 census measured whenever the card has room |
|
| `SPEC_TYPE=none` | the drafter off: hands back its 2,352.00 MiB of cache, 480.97 MiB of CUDA0 buffers and the 301.50 MiB of rollback planes it adds to the recurrent state (~3.1 GiB), at the cost of the ~+28 % decode the 2026-10-18 census measured whenever the card has room |
|
||||||
| `UBATCH_SIZE=2048` | +~1,306 MiB of compute buffers and +4.6 % prefill — and the rung that HALVED decode beside an armed drafter (167.2 → 109.2 t/s) |
|
| `UBATCH_SIZE=2048` | +4.6 % prefill and only ~406 MiB of compute buffers at THIS shape (the ~1,306 MiB the 786,432-pool census showed does not transfer) — and the rung that HALVED decode beside an armed drafter (167.2 → 109.2 t/s) |
|
||||||
| `CTX_SIZE=401408` | two 200,704 conversations: frees 4,802 MiB of cache — `contextWindow` MUST follow the per-slot number |
|
| `CTX_SIZE=401408` | two 200,704 conversations: frees 4,802 MiB of cache — `contextWindow` MUST follow the per-slot number |
|
||||||
| `CACHE_TYPE_V=f16` | exact V: +4,410 MiB at this pool with the drafter armed, which is a `cudaMalloc` death the seam refuses — legal only once the drafter or a slot is gone |
|
| `CACHE_TYPE_V=f16` | exact V: +4,410 MiB at this pool with the drafter armed, which is a `cudaMalloc` death the seam refuses — legal only once the drafter or a slot is gone |
|
||||||
| `CACHE_TYPE_K=q8_0` | the fully quantized pair (17,408 B/token): frees 4,410 MiB and moves the quantization error into the keys |
|
| `CACHE_TYPE_K=q8_0` | the fully quantized pair (17,408 B/token): frees 4,410 MiB and moves the quantization error into the keys |
|
||||||
@@ -127,6 +152,10 @@ minutes, 96 % GPU-util), the exact condition a bench window exists to exclude.
|
|||||||
`tests/frank_zealot_unit.bats`'s fit gate can see a boot that would die at `cudaMalloc`, so every retune keeps it
|
`tests/frank_zealot_unit.bats`'s fit gate can see a boot that would die at `cudaMalloc`, so every retune keeps it
|
||||||
green — and the first verbosity-4 ledger plus settled `nvidia-smi` of a new dtype belongs on this page, because
|
green — and the first verbosity-4 ledger plus settled `nvidia-smi` of a new dtype belongs on this page, because
|
||||||
projections drift.
|
projections drift.
|
||||||
|
The same trap one knob down: the ubatch 2048 → 1024 step handed back **~1,306 MiB** at the 786,432 / q8_0-pair
|
||||||
|
arm and **406 MiB** at the 602,112 / f16-K + q8_0-V boot (target compute 2,496.13 → 2,089.88, with CUDA0 going
|
||||||
|
UP 257 while CUDA_Host went down 663). Changing the dtype or the pool moves the compute buffers too, so a
|
||||||
|
credit measured at one shape is not a budget line at the next.
|
||||||
The two boots that priced non-KV: 2 × 262,144 **without** the projector — 20,190 used, KV 12,800 ⇒ non-KV
|
The two boots that priced non-KV: 2 × 262,144 **without** the projector — 20,190 used, KV 12,800 ⇒ non-KV
|
||||||
**7,390 MiB**; 3 × 196,608 **with** it — 22,972 used, KV 14,113 ⇒ non-KV **8,859 MiB**. The difference prices the
|
**7,390 MiB**; 3 × 196,608 **with** it — 22,972 used, KV 14,113 ⇒ non-KV **8,859 MiB**. The difference prices the
|
||||||
vision tower at **~1.4 GiB for a 918 MB file**, because the encoder's activation and compute buffers ride with it.
|
vision tower at **~1.4 GiB for a 918 MB file**, because the encoder's activation and compute buffers ride with it.
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
# rollback). It replaces the FreeToken seam of
|
# rollback). It replaces the FreeToken seam of
|
||||||
# 2026-10-05 (git tag frank-archon-freetoken-pr587-20261005) and pins what
|
# 2026-10-05 (git tag frank-archon-freetoken-pr587-20261005) and pins what
|
||||||
# flags alone do not say: the served window clears the harness worst case,
|
# flags alone do not say: the served window clears the harness worst case,
|
||||||
# the KV pool backs seqs x max-model-len at the declared cache dtype (an
|
# the retired per-card budget knobs are ABSENT (the pinned engine refuses
|
||||||
# engine HARD limit, not a ratio), the per-card VRAM pair stays inside the
|
# them at ExecStart), the pinned-host ledger has a ttm pages cap floor, the
|
||||||
# the pinned-host ledger has a ttm pages cap floor, the serve script ENFORCES
|
# serve script ENFORCES
|
||||||
# it and RAISES the knob itself when a reboot reset it (the cap's default is
|
# it and RAISES the knob itself when a reboot reset it (the cap's default is
|
||||||
# half of RAM), the served window is what models.yml must
|
# half of RAM), the served window is what models.yml must
|
||||||
# quote, the host-networking contract (no --publish), the image gate on a
|
# quote, the host-networking contract (no --publish), the image gate on a
|
||||||
@@ -146,20 +146,23 @@ nosudo_bin() {
|
|||||||
grep -q '^FRANK_ARCHON_TP=2$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_TP=2$' "$ENV_FILE"
|
||||||
grep -q '^FRANK_ARCHON_TP_WIRE=wht6$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_TP_WIRE=wht6$' "$ENV_FILE"
|
||||||
grep -q '^FRANK_ARCHON_SPEC_TOKENS=2$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_SPEC_TOKENS=2$' "$ENV_FILE"
|
||||||
# expert_tiered placement: vram_weights + the pinned host pool serve the
|
# expert_tiered placement: the pinned host pool plus whatever expert VRAM the
|
||||||
# per-rank resident set TOGETHER, so cutting the VRAM slab to pay for the
|
# budget resolver leaves serve the per-rank resident set TOGETHER, so the pool
|
||||||
# KV pool moves the pool with it. KV is QUANTIZED fp8 (the engine takes
|
# size is also the lever on which experts stay on the card. KV is QUANTIZED
|
||||||
# only bf16|fp8 — no per-tensor K/V split), the PLE n-gram table is pinned
|
# fp8 (the engine takes only bf16|fp8 — no per-tensor K/V split), the PLE
|
||||||
# in host RAM per Frank's law.
|
# n-gram table is pinned in host RAM per Frank's law. The per-card VRAM pair
|
||||||
|
# is NOT asserted here: 1.3.0 removed it and the resolver derives the split,
|
||||||
|
# so the pool's token count is a boot-ledger line — verified live by the
|
||||||
|
# capacity leg of scripts/probe-frank-archon-kv.py at every cutover.
|
||||||
grep -q '^FRANK_ARCHON_PLACEMENT=expert_tiered$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_PLACEMENT=expert_tiered$' "$ENV_FILE"
|
||||||
grep -q '^FRANK_ARCHON_HOST_POOL_MIB=44928$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_HOST_POOL_MIB=45568$' "$ENV_FILE"
|
||||||
grep -q '^FRANK_ARCHON_VRAM_WEIGHTS_MIB=[1-9]' "$ENV_FILE"
|
|
||||||
grep -q '^FRANK_ARCHON_VRAM_KV_MIB=[1-9]' "$ENV_FILE"
|
|
||||||
grep -q '^FRANK_ARCHON_KV_DTYPE=fp8$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_KV_DTYPE=fp8$' "$ENV_FILE"
|
||||||
grep -q '^FRANK_ARCHON_NGRAM_PLACEMENT=ram$' "$ENV_FILE"
|
grep -q '^FRANK_ARCHON_NGRAM_PLACEMENT=ram$' "$ENV_FILE"
|
||||||
# Prefix cache tiers (publisher pattern; disk tier sized for 2 slots).
|
# Prefix cache: pinned host RAM only (the disk tier was removed), and the
|
||||||
grep -q '^FRANK_ARCHON_PREFIX_HOST_MIB=8192$' "$ENV_FILE"
|
# step-sharing cap is stated explicitly — auto vs off is the difference
|
||||||
grep -q '^FRANK_ARCHON_PREFIX_DISK_MIB=65536$' "$ENV_FILE"
|
# between decode waiting one chunk and waiting a whole step.
|
||||||
|
grep -q '^FRANK_ARCHON_PREFIX_CACHE_MIB=8192$' "$ENV_FILE"
|
||||||
|
grep -q '^FRANK_ARCHON_BUSY_PREFILL_CHUNK=auto$' "$ENV_FILE"
|
||||||
# The pinned ledger (2 x pool + 47.7 GiB PLE + prefix host) must be
|
# The pinned ledger (2 x pool + 47.7 GiB PLE + prefix host) must be
|
||||||
# under the ttm pages cap, and the env states the floor the serve
|
# under the ttm pages cap, and the env states the floor the serve
|
||||||
# script enforces (>= 140,000 MiB — the kernel's own default cap, half of
|
# script enforces (>= 140,000 MiB — the kernel's own default cap, half of
|
||||||
@@ -170,7 +173,7 @@ nosudo_bin() {
|
|||||||
ttmt=$(awk -F= '/^FRANK_ARCHON_TTM_TARGET_MIB=/{print $2}' "$ENV_FILE")
|
ttmt=$(awk -F= '/^FRANK_ARCHON_TTM_TARGET_MIB=/{print $2}' "$ENV_FILE")
|
||||||
[ "$ttmt" -gt "$ttmm" ]
|
[ "$ttmt" -gt "$ttmm" ]
|
||||||
pool=$(awk -F= '/^FRANK_ARCHON_HOST_POOL_MIB=/{print $2}' "$ENV_FILE")
|
pool=$(awk -F= '/^FRANK_ARCHON_HOST_POOL_MIB=/{print $2}' "$ENV_FILE")
|
||||||
ph=$(awk -F= '/^FRANK_ARCHON_PREFIX_HOST_MIB=/{print $2}' "$ENV_FILE")
|
ph=$(awk -F= '/^FRANK_ARCHON_PREFIX_CACHE_MIB=/{print $2}' "$ENV_FILE")
|
||||||
# 2 pools + PLE 47.7 GiB (48,824 MiB) + prefix host, rounded up.
|
# 2 pools + PLE 47.7 GiB (48,824 MiB) + prefix host, rounded up.
|
||||||
ledger=$(( 2 * pool + 48824 + ph + 2048 ))
|
ledger=$(( 2 * pool + 48824 + ph + 2048 ))
|
||||||
[ "$ttmm" -ge "$ledger" ]
|
[ "$ttmm" -ge "$ledger" ]
|
||||||
@@ -179,47 +182,21 @@ nosudo_bin() {
|
|||||||
[ "$(awk -F= '/^FRANK_ARCHON_RAD_MIN_MIB=/{print $2}' "$ENV_FILE")" -gt 0 ]
|
[ "$(awk -F= '/^FRANK_ARCHON_RAD_MIN_MIB=/{print $2}' "$ENV_FILE")" -gt 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "the KV pool backs seqs x max-model-len at the declared cache dtype" {
|
@test "the retired budget knobs are absent from the env and the argv" {
|
||||||
# The engine's own hard limit: a request longer than the pool's token
|
# Not unused leftovers: the pinned engine REFUSES to start on any of them
|
||||||
# count is "accepted by the API and then refused as too large to ever fit
|
# (--vram-weights-mib/--vram-kv-mib went away at 1.3.0, the prefix-cache disk
|
||||||
# -- this is a hard limit, not a backing ratio". Rates are measured, not
|
# tier outright), and a unit that refuses at ExecStart sits in
|
||||||
# derived: per rank, kv_attn (13 layers) pages 26.00 KiB per 4 tokens at
|
# `activating (auto-restart)` while the port still looks alive from whatever
|
||||||
# fp8 and 52.00 KiB at bf16, while kv_qsa_bkey (13 layers) pages 3.25 KiB
|
# held it last. A stale line here is an outage, so it is asserted away.
|
||||||
# at BOTH — the QSA block key is an index, not attention state, and does
|
for key in FRANK_ARCHON_VRAM_WEIGHTS_MIB FRANK_ARCHON_VRAM_KV_MIB \
|
||||||
# not follow --kv-cache-dtype — so the rate is 7,488 B/token at fp8 and
|
FRANK_ARCHON_PREFIX_HOST_MIB FRANK_ARCHON_PREFIX_DISK_MIB; do
|
||||||
# 14,144 at bf16 (1.89x, not 2x). The dtype-independent terms also live in
|
! grep -q "^${key}=" "$ENV_FILE"
|
||||||
# the pool: ~110 MiB a sequence of recurrent state (kv_gdn_state 54 MiB x 2
|
! grep -q "$key" "$SERVE"
|
||||||
# copies + conv/tail/ple) and 448 MiB of prefix checkpoints (8 x 55.99).
|
done
|
||||||
# Verified against BOTH live boots: fp8 3543-330-448 = 2765 MiB -> 387,240
|
for flag in --vram-weights-mib --vram-kv-mib --prefix-cache-host-mib \
|
||||||
# tokens (ledger 386,904); bf16 6912-220-448 = 6244 MiB -> 462,946
|
--prefix-cache-dir --prefix-cache-disk-mib; do
|
||||||
# (ledger 462,752). Both within 0.1%.
|
! grep -q -- "$flag" "$SERVE"
|
||||||
kv=$(awk -F= '/^FRANK_ARCHON_VRAM_KV_MIB=/{print $2}' "$ENV_FILE")
|
done
|
||||||
seqs=$(awk -F= '/^FRANK_ARCHON_MAX_SEQS=/{print $2}' "$ENV_FILE")
|
|
||||||
maxlen=$(awk -F= '/^FRANK_ARCHON_MAX_MODEL_LEN=/{print $2}' "$ENV_FILE")
|
|
||||||
case "$(awk -F= '/^FRANK_ARCHON_KV_DTYPE=/{print $2}' "$ENV_FILE")" in
|
|
||||||
fp8) bpt=7488 ;;
|
|
||||||
bf16) bpt=14144 ;;
|
|
||||||
*) fail "unknown FRANK_ARCHON_KV_DTYPE" ;;
|
|
||||||
esac
|
|
||||||
tokens=$(( (kv - 110 * seqs - 448) * 1048576 / bpt ))
|
|
||||||
[ "$tokens" -ge $(( seqs * maxlen )) ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "the per-card VRAM pair stays inside the measured card ceiling" {
|
|
||||||
# The engine's OWN budget table, not a hand-picked reserve. Boot of
|
|
||||||
# 2026-10-13 at the pair 24000/5120: card 32,624 MiB (31.86 GiB), budgets
|
|
||||||
# claimed 29,120, `3.42 GiB is neither budgeted nor accounted — the
|
|
||||||
# driver's context, the activation arena and --gpu-headroom-mib come out of
|
|
||||||
# it; anything past those is throughput on the floor`, and `card 0 settled
|
|
||||||
# at 2.01 GiB free against 209.19 MiB (the 96.00 MiB --gpu-headroom-mib and
|
|
||||||
# 113.19 MiB kept for the static region)`. Claimable reserve above the
|
|
||||||
# engine's floor: 2,058 - 209 = 1,849 MiB, so the ceiling is 30,969 MiB.
|
|
||||||
# The 2026-10-11 bound of 29,120 ("keep >= 1 GiB free", card read as 31,856
|
|
||||||
# MiB) was MY reserve, which the engine never asked for; the shipped pair
|
|
||||||
# spends the difference and lands ~458 MiB above the floor.
|
|
||||||
w=$(awk -F= '/^FRANK_ARCHON_VRAM_WEIGHTS_MIB=/{print $2}' "$ENV_FILE")
|
|
||||||
kv=$(awk -F= '/^FRANK_ARCHON_VRAM_KV_MIB=/{print $2}' "$ENV_FILE")
|
|
||||||
[ $(( w + kv )) -le 30969 ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "the serve script wires the engine flags from the env" {
|
@test "the serve script wires the engine flags from the env" {
|
||||||
@@ -232,11 +209,13 @@ nosudo_bin() {
|
|||||||
grep -q -- '--max-model-len "$FRANK_ARCHON_MAX_MODEL_LEN"' "$SERVE"
|
grep -q -- '--max-model-len "$FRANK_ARCHON_MAX_MODEL_LEN"' "$SERVE"
|
||||||
grep -q -- '--placement "$FRANK_ARCHON_PLACEMENT"' "$SERVE"
|
grep -q -- '--placement "$FRANK_ARCHON_PLACEMENT"' "$SERVE"
|
||||||
grep -q -- '--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB"' "$SERVE"
|
grep -q -- '--host-pool-mib "$FRANK_ARCHON_HOST_POOL_MIB"' "$SERVE"
|
||||||
grep -q -- '--vram-weights-mib "$FRANK_ARCHON_VRAM_WEIGHTS_MIB"' "$SERVE"
|
|
||||||
grep -q -- '--vram-kv-mib "$FRANK_ARCHON_VRAM_KV_MIB"' "$SERVE"
|
|
||||||
grep -q -- '--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE"' "$SERVE"
|
grep -q -- '--kv-cache-dtype "$FRANK_ARCHON_KV_DTYPE"' "$SERVE"
|
||||||
grep -q -- '--prefix-cache-host-mib "$FRANK_ARCHON_PREFIX_HOST_MIB"' "$SERVE"
|
grep -q -- '--prefix-cache-mib "$FRANK_ARCHON_PREFIX_CACHE_MIB"' "$SERVE"
|
||||||
grep -q -- '--prefix-cache-disk-mib "$FRANK_ARCHON_PREFIX_DISK_MIB"' "$SERVE"
|
grep -q -- '--busy-prefill-chunk "$FRANK_ARCHON_BUSY_PREFILL_CHUNK"' "$SERVE"
|
||||||
|
# Interleave is opt-in: it reaches argv only through the guarded array, so a
|
||||||
|
# 0 in the env leaves the engine's own default in place.
|
||||||
|
grep -q -- 'PREFILL_ARGS=(--prefill-interleave "$FRANK_ARCHON_PREFILL_INTERLEAVE")' "$SERVE"
|
||||||
|
grep -qF -- '"${PREFILL_ARGS[@]}"' "$SERVE"
|
||||||
grep -q -- '--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT"' "$SERVE"
|
grep -q -- '--ngram-placement "$FRANK_ARCHON_NGRAM_PLACEMENT"' "$SERVE"
|
||||||
grep -q -- '--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS"' "$SERVE"
|
grep -q -- '--num-speculative-tokens "$FRANK_ARCHON_SPEC_TOKENS"' "$SERVE"
|
||||||
# The boot-ladder escape hatch is opt-in: unset renders NO extra argv.
|
# The boot-ladder escape hatch is opt-in: unset renders NO extra argv.
|
||||||
@@ -261,7 +240,10 @@ nosudo_bin() {
|
|||||||
grep -q -- '--device /dev/kfd' "$SERVE"
|
grep -q -- '--device /dev/kfd' "$SERVE"
|
||||||
grep -q -- '--device /dev/dri' "$SERVE"
|
grep -q -- '--device /dev/dri' "$SERVE"
|
||||||
grep -q -- '-v "$FRANK_ARCHON_MODEL_DIR":/models:ro' "$SERVE"
|
grep -q -- '-v "$FRANK_ARCHON_MODEL_DIR":/models:ro' "$SERVE"
|
||||||
grep -q -- '-v "$FRANK_ARCHON_STATE_DIR":/data' "$SERVE"
|
grep -q -- '-v "$FRANK_ARCHON_STATE_DIR/tune":/opt/radiance/share/radiance/tune' "$SERVE"
|
||||||
|
# No /data mount: the prefix cache lives in pinned host RAM now, so the only
|
||||||
|
# host state the container writes is the rad-tune cache above.
|
||||||
|
! grep -q -- ':/data ' "$SERVE"
|
||||||
grep -q -- '-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro' "$SERVE"
|
grep -q -- '-v "$FRANK_ARCHON_TEMPLATE":/templates/template.jinja:ro' "$SERVE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user