diff --git a/scripts/run-qwen38-bf16.sh b/scripts/run-qwen38-bf16.sh index ca64cb9..076c624 100755 --- a/scripts/run-qwen38-bf16.sh +++ b/scripts/run-qwen38-bf16.sh @@ -94,9 +94,10 @@ # bf16 container, kldref only), FRANK_QWEN38_CAMPAIGN (holds kld-ref/ and # calib/), FRANK_QWEN38_KLD_CORPUS, FRANK_QWEN38_TPL (the template copy # the container reads through /models), FRANK_QWEN38_LOG_DIR, and -# FRANK_QWEN38_MNBT — the step size shared by kldref and score (default +# FRANK_QWEN38_MNBT — the step size every mode boots at (default # 1,024: the file tier's ceiling is 2,048 and production runs there, but on # this payload the arena charged for a wider step is taken from the cache), +# the slot count inherited as FRANK_ARCHON_MAX_SEQS — no per-mode literals — # and FRANK_QWEN38_MAX_MODEL_LEN — the window every mode boots at (32,768; # see the corpus census above, and raise it together with the corpus). # kldref refuses (exit 2) when the longest record of the corpus it is about to @@ -162,6 +163,15 @@ SERVICE=frank-archon # here once starved the recorder. The `:?` guards keep an empty env fatal. HOST_POOL_MIB="${FRANK_ARCHON_HOST_POOL_MIB:?FRANK_ARCHON_HOST_POOL_MIB must be set}" GPU_HEADROOM_MIB="${FRANK_ARCHON_GPU_HEADROOM_MIB:?FRANK_ARCHON_GPU_HEADROOM_MIB must be set}" +# The slot count, from the same file that owns the card split: production runs +# four slots and every mode measures at production's geometry. A per-mode +# literal here is what let calib ask for eight slots and then starve its own +# cache. The `:?` guard keeps an empty env fatal, as for the card split. +MAX_SEQS="${FRANK_ARCHON_MAX_SEQS:?FRANK_ARCHON_MAX_SEQS must be set}" +if ! [[ "$MAX_SEQS" =~ ^[0-9]+$ ]]; then + echo "REFUSED: FRANK_ARCHON_MAX_SEQS must be a slot count (got: $MAX_SEQS)" >&2 + exit 2 +fi # ONE step size for both logits modes. The file tier streams only at <=2,048 and # the gate scores file-tier payloads (the served iq4r, the arms) against the @@ -232,7 +242,7 @@ case "$MODE" in # room the corpus needs. Corpus read-only, record dir rw. ARGS+=(--model "$MODEL_IN" --kld-record /data/kld-ref --kld-corpus /data/kld.jsonl - --max-num-seqs 4 --max-num-batched-tokens "$MNBT") + --max-num-seqs "$MAX_SEQS" --max-num-batched-tokens "$MNBT") MOUNTS+=(-v "$KLD_CORPUS:/data/kld.jsonl:ro" -v "$KLD_REF_DIR:/data/kld-ref") ;; @@ -247,17 +257,26 @@ case "$MODE" in fi ARGS+=(--model "$MODEL_IN" --kld-ref /data/kld-ref --kld-out "/data/out/$(basename "$SCORE_OUT")" - --max-num-seqs 4 --max-num-batched-tokens "$MNBT") + --max-num-seqs "$MAX_SEQS" --max-num-batched-tokens "$MNBT") MOUNTS+=(-v "$KLD_REF_DIR:/data/kld-ref:ro" -v "$OUT_DIR:/data/out") ;; calib) - # Calibration is exempt from the shared step: the tap counts pooled - # positions and nothing downstream is compared against a step size, so the - # wide step is free throughput (a disk-tier step costs the same at 1 token - # as at 64k). + # Calibration rides the shared step like every other mode. The old + # exemption — eight slots at MNBT 65,536 for "free throughput", because + # "a disk-tier step costs the same at 1 token as at 64k" — is false: the + # step's activation arena is billed on the card, not on the disk. The + # engine's own ledger for this container: at MNBT 1,024 the arena is + # 504 MiB and the card claims 30.87 GiB (weights 28.90 GiB of it); at + # 65,536 the arena is 10.65 GiB (fixed region 1.25 GiB), the claim falls + # to 16.85 GiB, the experts shrink to 10.98 GiB and the KV to 271 MiB — + # one slot's worth of cache for eight slots, and the boot dies at + # "startup stopped: out of memory" (measured 2026-10-29). A wide step + # buys throughput with the expert slab, so price it like any other + # VRAM knob. The slots follow frank-archon.env's FRANK_ARCHON_MAX_SEQS + # through MAX_SEQS, exactly as kldref and score do. ARGS+=(--model "$MODEL_IN" --port 7770 - --max-num-seqs 8 --max-num-batched-tokens 65536) + --max-num-seqs "$MAX_SEQS" --max-num-batched-tokens "$MNBT") MOUNTS+=(-v "$CALIB_DIR:/data/calib") TAPENV=(-e RADIANCE_CALIB_DIR=/data/calib -e RADIANCE_CALIB_TOKENS=12000000) diff --git a/tests/qwen38_reference.bats b/tests/qwen38_reference.bats index d60f138..57cf34e 100755 --- a/tests/qwen38_reference.bats +++ b/tests/qwen38_reference.bats @@ -247,16 +247,19 @@ flag_value() { [ ! -d "$L" ] } -@test "the reference and a score pass ride ONE step size, legal on the file tier" { +@test "every mode rides ONE step size and ONE seat count, legal on the file tier" { # The gate's claim is one shape; that shape's ceiling is set by the tightest # payload it boots, and the served iq4r and every arm are file-tier # containers, which stream only at <=2048. A reference recorded above that is - # a KL between two shapes, not two weights. + # a KL between two shapes, not two weights. Calib used to exempt itself from + # the shared step; the exemption cost the container its own cache, so the + # test now holds every mode to the same two numbers. M="$BATS_TEST_TMPDIR/models" C="$BATS_TEST_TMPDIR/campaign" run env FRANK_QWEN38_MODELS="$M" FRANK_QWEN38_CAMPAIGN="$C" bash "$RUNNER" kldref --dry-run [ "$status" -eq 0 ] ref_step="$(flag_value --max-num-batched-tokens <<< "$output")" + ref_seats="$(flag_value --max-num-seqs <<< "$output")" [ -n "$ref_step" ] [ "$ref_step" -le 2048 ] run env FRANK_QWEN38_MODELS="$M" FRANK_QWEN38_CAMPAIGN="$C" \ @@ -271,10 +274,16 @@ flag_value() { run env FRANK_QWEN38_MODELS="$M" FRANK_QWEN38_CAMPAIGN="$C" FRANK_QWEN38_MNBT=1024 \ bash "$RUNNER" score "$M/rad/arm-w5nl64.rad" "$C/scores/arm1.json" --dry-run [ "$(flag_value --max-num-batched-tokens <<< "$output")" = "1024" ] - # calibration is exempt: grams are not logits, so the tap keeps the wide step + # calibration rides the shared step too. Its old exemption (8 seats at + # MNBT 65,536, "free throughput") is what made the container refuse to + # boot: at that step the engine charges a 10.65 GiB activation arena to + # the card, the experts fall to 10.98 GiB and the KV to 271 MiB — + # "0.0 full-length sessions", "startup stopped: out of memory", measured + # 2026-10-29 while kldref on the shared step ran 16 hours without fault. run env FRANK_QWEN38_MODELS="$M" FRANK_QWEN38_CAMPAIGN="$C" FRANK_QWEN38_MNBT=1024 \ bash "$RUNNER" calib --dry-run - [ "$(flag_value --max-num-batched-tokens <<< "$output")" = "65536" ] + [ "$(flag_value --max-num-batched-tokens <<< "$output")" = "1024" ] + [ "$(flag_value --max-num-seqs <<< "$output")" = "$ref_seats" ] # a step size that is not a token count is refused, never handed to the engine run env FRANK_QWEN38_MNBT=broad bash "$RUNNER" kldref --dry-run [ "$status" -eq 2 ]