Commit Graph
8 Commits
Author SHA1 Message Date
Frank 99ed1aca9a docs: reboot-tested the frank-medium trio
Rebooted dankserver unattended and verified without any manual step: all three
units active 59 s after boot, both replicas healthy ~3.5 min after boot, real
completion through :7770 — the failure mode this repo has been bitten by before
(a service that only ever ran from compose and stayed dark after a reboot).
Records why it works: [Install] WantedBy=default.target wired into the
generator's default.target wants, plus Linger=yes, plus a disk-backed compile
cache so a cold boot needs no warm-up beyond the model load.
2026-09-16 06:00:15 -07:00
Frank 24687f561f docs: frank-medium capacity budget and the CHUNK sweet spot
A 25-minute soak with three concurrent large-context agent loops (each turn
re-sending a ~30k-token document, growing history) came back clean — 155
requests, 155 answers, no errors, no failover, both replicas steady — but only
25% of turns hit the prefix cache, the rest paying a 13.9 s median re-prefill.
That is the capacity budget showing: 122,636 KV tokens per card is about two
30k-token conversations with their cached prefixes, and a third family on the
same card evicts.

Chasing the obvious lever disproved it. Available KV per card is 5.44 GiB at
CHUNK=8192, 4.22 GiB at 16384 and 4.16 GiB at 4096 — where the engine refuses
to start. The budget is not monotonic in the chunk size, so 8192 is a sweet
spot rather than a compromise and freeing KV needs another card, not a knob.
2026-09-16 05:49:54 -07:00
Frank d8189b65f4 docs: record the proxy's failover behaviour and how to verify it 2026-09-16 05:29:45 -07:00
Frank 4d37f8ca65 frank-medium: measure speculative depth on the repo's own code corpus
Upstream ships dflash depth 7 as a content-dependent default measured for TP=2
on their corpus. Re-measured on one card here, two runs per setting, 16
repo-derived prompts at 512 output tokens:

  SPEC=7  conc1 46.2 tok/s, TPOT 20.8 ms, 3.86 tok/update
          conc4 118.7 / 127.0 tok/s
  SPEC=5  conc1 41.5 tok/s, TPOT 23.1 ms, 3.41 tok/update
          conc4 136.1 / 129.4 tok/s

Step time is nearly identical at both depths (~79 ms vs ~80 ms single stream):
7 wins by landing more tokens per step, 5 wins at conc 4 by ~8% because more
narrow verify steps pack better. Depth 7 stays — this fleet is interactive
agent loops where per-turn latency is what is felt — and the runbook now
records the numbers and the one-line switch for a batch-first workload.
2026-09-16 05:23:09 -07:00
Frank 8b79766d81 docs: record why CHUNK stays at 8192 on the single-GPU replicas
Raising the prefill chunk to 16384 grows the arena enough that the KV cache
falls to 4.22 GiB against the 5.21 GiB a 114688-token context needs, so the
engine refuses to start. Measured single-card prefill at 8192 is ~2.5k tok/s
(~15k-token prompt, 5992 ms TTFT); the trade would mean cutting context for
unmeasured prefill gain, so the default stands.
2026-09-16 04:58:47 -07:00
Frank 83625e84a7 frank-medium: route by workload — spread batches, pin agent loops
The two replicas behind :7770 were on plain round-robin, which throws away
prefix-cache hits: an agent loop re-sends its system prompt and file context
every turn, and alternating replicas means every other turn pays a cold
prefill. Measured with 90k-token contexts, warm-turn TTFT was 2676 ms.

Pinning everything to one replica is not the answer either — a cold batch
(the shape a benchmark or a burst of parallel subagents produces) then loses a
card's worth of prefill: 16 requests took 30.1 s pinned against 18.6 s spread.

So the policy routes by request shape. A continuation (more than one message —
the agent-loop signature) is pinned to the replica that served its prefix;
anything else spreads across the cards by counter. Measured: 19.97 s for the
burst and 1095 ms warm-turn TTFT — the best of both, without a regression on
either workload.

The policy lives in proxy/routing.py, separate from the HTTP plumbing in
proxy/affinity-proxy.py, so it can be tested without aiohttp, a network or a
GPU. tests/frank_medium_proxy.bats covers it, and it earned its keep: the
first version hashed fresh prefixes to pick a card, which sends every member of
a same-prefix burst to one card (29.8 s, measured), and a stale index in the
pin path returned 500 on every continuation. Both are now assertions.

ROUTING=roundrobin and ROUTING=affinity stay available to re-measure the
choice on this host; the default is adaptive.
2026-09-16 04:45:21 -07:00
Frank 7ce6e96bc5 docs: record the KV_MEM=0 passthrough trap in the frank-medium runbook 2026-09-16 03:58:48 -07:00
Frank 4fca739bf8 frank-medium: deploy two single-GPU replicas — TP=2 is blocked by PCIe atomics
The radiance MXFP4 stack cannot run TP=2 on this host. RCCL's collective
kernels carry a hidden hostcall-buffer parameter, and ROCr refuses to
dispatch them on a device without PCIe atomics: the AQL dispatch fails with
hipErrorIllegalState ("the operation cannot be performed in the present
state"), which is what every two-rank collective hit. The second R9700 sits
behind the chipset bridges 05:00.0/06:09.0, which advertise
`AtomicOpsCap: Routing-` — a read-only capability, so no software can enable
atomic routing on that path and the driver's
pci_enable_atomic_ops_to_root() fails for that card. The first card, on CPU
root port 00:01.1, has atomics enabled.

Ruled out: kernel version (7.0.0-28/-30/-31 identical, after a full upgrade),
iommu=pt, P2P hardware (45.3 GB/s between the cards), the shipped librccl (a
from-source rebuild reproduces the failure at the same call path), vLLM and
pynccl (a bare two-rank torch.distributed allreduce fails the same way), all
NCCL transport knobs, and single-rank tests (NCCL short-circuits at
world_size=1, so one-card success proves nothing).

Deployment: three rootless Quadlets — frank-medium-a (:7771, card 1),
frank-medium-b (:7772, card 2), both TP=1 at 114688 context (262144 and
131072 do not fit one card's KV) with vLLM-profiled KV — and
frank-medium-proxy (:7770), a round-robin that preserves the fleet contract
of one endpoint and one served model name. frank-medium.container stays as
the TP=2 target for a host whose second card is atomic-capable; the deploy
handler does not install it and trashes any stale copy.

Measured through the proxy (vllm bench serve, random dataset, --ignore-eos):
conc 1 42.8 tok/s, conc 4 147.6 tok/s, conc 8 230.8 tok/s, 32k prefill at
~2.8k tok/s per card, TPOT p50 23.6-28.8 ms.

Also: healthcheck reads PORT so one probe serves all three units, the hermes
example and the harness models.yml drop to the real 114688 context, and the
runbook records the full evidence chain.
2026-09-16 03:47:11 -07:00