2026-09-24, 03:11-11:11 IDT, three DGX Sparks (GB10), TP_SIZE=3 throughout. Plan: merged-new.md. Running log with every experiment: overnight-progress.md. Raw evidence (per-request JSONL, summaries, acceptance joins, boot logs, env files, profiles): results/overnight-20260924-0311/.
Result: the fleet serves a configuration that is 17-40 % faster single-stream and 19 % faster at C4
than the one it started with, validated on two boots with no measured quality regression.
Biggest levers: TP3/EP1 (+8-12 %), the wo_a FP8 twin with DROP/MID, k=5 with the confidence cap
(code), and Engram prefetch. Two operational defects were found and fixed on the way: rank 2 was running
a different SGLang build from ranks 0/1, and the packed Engram shards were missing on every rank.
| workload (5 reps, 512 tokens, from spark2) | original (b0) | final F1 (fresh tune) | final F2 (cache reuse) | change b0 -> F2 |
|---|---|---|---|---|
| C1 prose, greedy (tok/s) | 29.28 | 34.29 | 34.15 | +16.6 % |
| C1 prose2, greedy (added at E2; E2 value in first column) | (29.56) | 32.27 | 32.56 | (+10.1 % vs E2) |
| C1 code, greedy | 44.65 | 62.69 | 62.24 | +39.4 % |
| C1 sampled chat (T=0.7) | 28.87 | 36.57 | 37.20 | +28.9 % |
| C4 aggregate, 2 prose + 2 code | 63.78 | 76.03 | 75.79 | +18.8 % |
| C4 per-stream decode | 19.46 | 24.52 | 24.31 | +24.9 % |
| TTFT, C1 (52-token prompt) | 0.28-0.30 s | 0.25-0.29 s | 0.25-0.29 s | unchanged |
| bs=1 step, prose / code | 73.2 / 74.0 ms | 58.7 / 68.5 ms | 59.0 / 69.7 ms | -14 / -4 ms (k 3 -> 5) |
| acceptance, prose / code | 2.17 / 3.27 | 2.05 / 4.00 | 2.04 / 3.98 | code +22 % (k=5) |
| effective KV pool (tokens) | 491,520 | 658,176 | 749,824 (pin) | see memory section |
Quality on the final configuration (F1 and F2, plus E8 with identical settings): 8/8 checkable tasks, 8/8 under 4-way concurrency, greedy 256-token repeat 1 distinct of 3, needles found at 28.7k and 95.5k (F1) and at 190.9k prompt tokens (E8) with prose/code/sampled requests running alongside. No NaN/inf/OOM/traceback lines in any final-configuration log. With autotune reuse, the greedy code text was byte-identical between F1 and F2.
The fleet is left serving the final configuration from the default .env via ./start.sh (F3,
rebooted ~09:47 after the E11 extra experiment; same settings and tactics as F2).
scripts/overnight/bench.sh LABEL 5 512 runs benchmarks/overnight_bench.py
from spark2 against the head: one discarded warm-up per workload and one C4 warm-up wave, then
5 repetitions per workload, 512 max tokens, thinking off. Workloads: greedy prose (lighthouse essay),
greedy prose2 (fishing-village story, added at E2), greedy code (LRU cache + tests), sampled chat
(T=0.7, top_p=0.95); C4 = four concurrent requests (2 prose + 2 code) x 5 waves.usage.completion_tokens; never SSE event counts. C1 decode tok/s =
(tokens - 1) / (last content delta - first content delta); C4 aggregate = total completion tokens /
wave wall time. Acceptance and step time come from the head's Decode batch lines inside each phase
window (scripts/overnight/accept.py: step = accept_len x bs /
gen throughput).scripts/overnight/quality.sh LABEL [needle_k,...] runs benchmarks/overnight_quality.py:
8 checkable tasks (arithmetic, JSON schema, generated is_prime executed against 10 cases, sorting,
counting, facts), the same 8 fired 4 at a time, a greedy repeat check, and needle retrieval..env + the listed changes) in results/.../envs/, booted with
ENV_FILE=<file> ./start.sh serve. start.sh sources the env file with set -a, so command-line
overrides of variables that .env defines are silently ignored; use an env file.| issue found | action |
|---|---|
Packed Engram shards absent on all ranks (packed=False) |
spark2's old TP2 shards (101.4 GB) moved to spark1:/home/mia/archive/dsv41-engram-tp2-spark2/ (SHA-256 verified both sides, SHA256SUMS there; pointer at spark2:/home/zurih/dsv41-engram/MOVED.txt); TP3 shards packed on all three ranks; packed=True for layers 1 and 14 on ranks 0/1/2 after restart |
Rank 2 ran a different SGLang build (spark3's lmsysorg/sglang:dev-dsv41 = 381b27ff / da64c5cbb, 40 source files different from ranks 0/1 incl. deepseek_v4.py and the DSpark worker) |
spark3's images kept as lmsysorg/sglang:dev-dsv41-da64c5cbb-20260911 and dsv41-3x-spark:mixed-da64c5cbb-20260924; the head's base (37939c26) loaded onto spark3; overlay rebuilt everywhere |
| Autotune caches discarded twice per boot | adapter/autotune_keep.py ported, plus two fixes (below) |
| step | change | evidence |
|---|---|---|
| B1 | packed Engram + identical images on all ranks | C4 +5 %, code +2 %; Engram waiting gone from the profile |
| E2 | DSV41_WO_A_W8=1, DSV41_WO_A_W8_DROP=1, DSV41_WO_A_W8_MID=1 (target layers only) |
bs=1 step 72 -> 68-69 ms, bs=4 131.5 -> 125.6 ms; KV pool back to the 750k pin (DROP frees 1280 MB/rank) |
| E4 | DSPARK_BLOCK_SIZE=5 + DSV41_VERIFY_CAP=conf:0.1 + DSV41_BLOCK_VERIFY=1 |
code +9.6 %, prose/sampled/C4 neutral vs k=3 |
| E5 | DSV41_DRAFT_HEAD_FP8=1 |
step -0.1 to -1.3 ms on all C1 workloads, +210 MiB |
| E6b | DSV41_ENGRAM_PREFETCH=1 (check-mode pass first: 0 differing gathers on all ranks) |
step -2.3 to -2.9 ms everywhere, C1 +3.7 to +4.2 % |
| E8 | EP_SIZE=1 (TP3/EP1) |
C1 +7.8 to +12 %, C4 +9.7 %; NCCL 12.9 -> 5.6 ms/step |
| infra | DSV41_AUTOTUNE_KEEP=1 (fixed port) |
all three ranks reused both caches on E7, E9 and the final repeat boot; greedy output reproducible across boots |
| experiment | result |
|---|---|
E1: wo_a W8 twin without DROP |
does not boot at fraction 0.95: +688 MiB leaves "no GPU memory for the KV cache ... minimum viable 0.9503" |
| E1b: W8 + DROP as shipped | booted but acceptance 1.0 (C1 ~14 tok/s): dev-dsv41's draft runs its own einsum on self.wo_a.weight, which DROP had replaced by a zero tag. Fixed in the adapter (draft left on bf16 in bridge mode) |
| E1c: W8 + DROP without MID | C4 -8 %: 16-row verifies fall to per-call dequantize; MID fixes it (E2) |
| E3: k=5 without the cap | code +11 %, prose -8 to -16 %, C4 -10 % |
E7: DSV41_DRAFT_TAU=0.8 |
sampled +1.2 % pooled over 15 runs, inside noise; not a demonstrated win, left off |
E9: conf:0.2 instead of 0.1 |
mixed within noise, C4 -2.8 % |
| E10: k=3 without cap on EP1 | code -10.5 %, prose2 -3.3 %, prose/C4 equal: k=5 + conf:0.1 stays |
E11: draft wo_a einsum on the fp8 twin (DSV41_WO_A_W8_DRAFT=1, new, default off) |
C1 -0.8 to -1.3 %, C4 +1.3 % on the same tactics; step -1.5 to +0.2 ms, prose acceptance dipped; left off |
adapter/wo_a_w8.py: in einsum-bridge mode (dev-dsv41) the draft's wo_a is never dropped (the draft
never reaches the shared dispatch, so DROP broke it) and by default not twinned; the new
DSV41_WO_A_W8_DRAFT=1 (default off, forwarded by start.sh, volatile for autotune) routes the
draft's own einsum to a twin instead (E11, neutral).adapter/autotune_keep.py (ported from knapcio 4d8f4c0):
SGLANG_RUN_ID (a per-boot timestamp the launcher sets) from the fingerprint; with it,
no sidecar could ever match and nothing was reused;DSV41_DRAFT_HEAD_FP8, DSV41_ENGRAM_PREFETCH(_CHECK).
Tests extended for (1) and (2).start.sh: forwards DSV41_AUTOTUNE_KEEP and DSV41_ENGRAM_PREFETCH_CHECK on head and workers, and
SGLANG_DSPARK_FOLDED_SAMPLING only when set (unset stays the engine's AUTO, which chose the folded
sampler on every boot tonight)..env (installed 08:50; the previous file is state/env.pre-overnight-20260924). Changed keys only;
everything else is unchanged (TP_SIZE=3, NNODES=3, MEM_FRACTION_STATIC / HEAD_MEM_FRACTION_STATIC 0.95,
MAX_TOTAL_TOKENS 750000, MAX_RUNNING_REQUESTS 4, CHUNKED_PREFILL_SIZE 1024, DSV41_CACHE_GIB 0,
DSV41_MXFP8_BACKEND b12x, SGLANG_FLASHINFER_MOE_FUSED_FINALIZE 0, PYTORCH_CUDA_ALLOC_CONF
expandable_segments:False, CONTEXT_LENGTH 262144, NCCL settings as before):
EP_SIZE=1
DSV41_WO_A_W8=1
DSV41_WO_A_W8_MID=1
DSV41_WO_A_W8_DROP=1
DSV41_DRAFT_HEAD_FP8=1
DSV41_VERIFY_CAP=conf:0.1
DSV41_BLOCK_VERIFY=1
DSV41_ENGRAM_PREFETCH=1
DSPARK_BLOCK_SIZE=5
DSV41_AUTOTUNE_KEEP=1
Images: dsv41-3x-spark:local rebuilt from this working tree on all three nodes on the common base
lmsysorg/sglang:dev-dsv41@sha256:3dbc3130… (public on Docker Hub; arm64 image id 37939c26c0…,
2026-09-10, SGLang 0.0.0.dev0,
FlashInfer 0.6.18). Packed Engram: head ~/dsv41-engram/engram-l{1,14}-r0of3.bin, workers
/home/zurih/dsv41-3x-spark/engram/engram-l{1,14}-r{1,2}of3.bin (31.5 GiB each).
Engine-side facts on the final boots: folded DSpark sampling active (AUTO), verify cap captured for
M=6/12/18/24, packed=True on all ranks, autotune caches reused on the repeat boot.
# build (all three nodes) and serve the final configuration
./start.sh build
./start.sh # = serve, reads .env
# benchmark from spark2 and join acceptance/step from the head log
RESULTS_DIR=docs/results/<dir> scripts/overnight/bench.sh <label> 5 512
# only some C1 workloads / phases
PHASES=c1 C1_WORKLOADS=chat_sampled RESULTS_DIR=… scripts/overnight/bench.sh <label> 10 512
# quality gate incl. needles (k tokens)
RESULTS_DIR=… scripts/overnight/quality.sh <label> 30,100,200
# an experiment arm = .env plus changes
RESULTS_DIR=… BASE_ENV=.env scripts/overnight/mkenv.sh <name> KEY=VAL …
ENV_FILE=$RESULTS_DIR/envs/<name>.env ./start.sh serve
# decode profile of rank 0 (send one request from a worker while it waits), analyse on spark2
scripts/profile/profile_decode.sh 45 /tmp/prof
| item | per-rank effect |
|---|---|
wo_a DROP (40 target layers) |
bf16 copies released: -1280 MB; fp8 twins kept: +640 MB + scales. Net about -640 MB vs the original. The draft's 3 wo_a stay bf16 (96 MB). Twins without DROP (+688 MiB) do not fit at 0.95. |
| draft LM head fp8 twin | +210 MiB (43136 x 5120 e4m3 + scales); bf16 head kept (the target uses it) |
| Engram prefetch | side stream only; no measurable change |
| EP1 vs EP3 | same expert bytes per rank; KV calculation 929k (E8) vs 957k (E5, EP3): within boot variance |
| KV pool (effective) | original boot 491,520; B1 226,816; W8+DROP boots at the 750k pin (749,824); final boots 658,176 (F1) and 749,824 (F2). The engine sizes from the minimum free memory across ranks, which varies by ~0.5 GB between boots; below the pin the pool shrinks rather than failing. 190,886-token needle passed on E8. |
| host headroom while serving | head ~2 GB MemAvailable, spark2 ~7 GB, spark3 ~3-4 GB (unchanged from the original); head PSI "some" avg10 peaked at 1.33 during a 190k-token prefill |
cp state/env.pre-overnight-20260924 .env && ./start.sh. The rebuilt image keeps
every adapter off unless its variable is set, so the old .env reproduces the old serving flags on
converged images with packed Engram. (Deliberately not restoring the mixed-build fleet: the original
spark3 overlay is kept as dsv41-3x-spark:mixed-da64c5cbb-20260924 if it is ever needed.).env and ./start.sh: EP_SIZE=3; DSPARK_BLOCK_SIZE=3 with
DSV41_VERIFY_CAP=0; DSV41_WO_A_W8=0 (turns MID/DROP off too); DSV41_DRAFT_HEAD_FP8=0;
DSV41_ENGRAM_PREFETCH=0; DSV41_AUTOTUNE_KEEP=0 (stock discard-and-retune).~/.cache/sglang/flashinfer/autotune/0.6.18/sm121/*/rank_*.{json,launch}
on all three nodes; the next boot retunes./home/mia/archive/dsv41-engram-tp2-spark2/ (SHA256SUMS).wo_a on bf16, 2.4 ms/step: tried as E11 (DSV41_WO_A_W8_DRAFT=1, einsum proxy);
neutral. A profile of that switch should check the dispatch and why draft acceptance moved.da64c5cbb/canary image as a whole-fleet upgrade, more request slots / C8,
SPS/STS tables, folded-result fence, per-position cap thresholds, k=4 + cap.In normal use of the final configuration, a single new prompt of at least ~200k tokens ran spark1
out of memory during prefill (1024-token chunks; first NV_ERR_NO_MEMORY at 13:23, host hung until
a hard reset at 14:05). The KV cache was only ~31 % full: the per-chunk indexer transient was the
peak. The campaign's long-context check had stopped at 191k, so the range 191k-262k was never
validated on this stack, and no memory guard was running.
Change: CHUNKED_PREFILL_SIZE=768 (default in .env.example). The next boot got the 750k KV pin
with a 1.24M budget and the head at ~5.2 GB MemAvailable (was ~2 GB). Not yet measured: the
largest prompt that is safe at 768, and whether EP1 or the larger KV cache lowered the ceiling
compared with the pre-campaign configuration (208k verified there, 256k failed). Until that is
measured, run scripts/verify/memguard.py on the head for long-context work.