Skip to content

offload-matrix: Tier 0 + Tier 1 test suite, and fix a partial-cache blind spot - #825

Closed
noonghunna wants to merge 5 commits into
masterfrom
test/offload-matrix-suite
Closed

offload-matrix: Tier 0 + Tier 1 test suite, and fix a partial-cache blind spot#825
noonghunna wants to merge 5 commits into
masterfrom
test/offload-matrix-suite

Conversation

@noonghunna

Copy link
Copy Markdown
Owner

Closes the first two tiers of #824, and fixes a detector defect found while validating the engine work that motivated it.

The fix: CACHE_PARTIAL

CACHE_DISABLED keyed on the presence of a [moe-cache] enabled: line. A per-device budget failure still prints that line while one GPU runs with no pool at all — measured live on the reference rig: CUDA0 got no budget, CUDA1 allocated a 69-slot pool, enabled: printed, and the arm reported OK. Throughput on such a run blends a cached and an uncached device and is comparable to neither.

Detection now counts devices that actually got a pool against the device count:

pooled devices status
0 CACHE_DISABLED (unchanged)
0 < n < NGPU CACHE_PARTIAL (new)

Tier 0 — static, 9 checks, ~1.2 s

No server, no GPU, no model. Each check guards a defect that actually shipped in this harness during development (all six are listed in #824):

  • column parity — header width == emit_row values + status, and the width must derive from $HDR. Guards the printf that carried 32 specifiers for 33 arguments: bash re-ran the format for the surplus arg, so every arm wrote a short row plus a junk status-only row.
  • status-enum parity, sweep ↔ renderer. This one has already earned itself — CACHE_DISABLED shipped with no renderer annotation within an hour of being added, and it caught CACHE_PARTIAL in this very PR.
  • pairing key includes shape — workload shape flips the sign of speculative results, so a mispair manufactures a gain that does not exist.
  • plus: syntax both halves, MODEL mandatory, engine-scope refusal, PLAN=1 boots nothing, renderer survives a mixed TSV, and the suite leaves no artifacts in the repo.

Mutation-tested: deleting the CACHE_DISABLED annotation reds the suite with the right message. A green run is not evidence that a check can fail.

Tier 1 — mocked server, 5 scenarios, ~15 s

Runs the real sweep end-to-end against a fake llama-server that emits the exact log lines the script scrapes and serves the two endpoints it calls. No GPU, no model, no engine — but boot → drive → scrape → emit → render all execute, which is where the silent defects live.

scenario asserted status
healthy OK
partial CACHE_PARTIAL — the regression guard for the fix above
nobudget CACHE_DISABLED, remedy named
bypass INVALID_BYPASS
notokens NO_TOKENS

Each case also asserts row invariants (field count == header count; OK implies non-zero throughput; bypass>0 implies not OK), and a final pass proves the renderer surfaces every failure status and separates them from the conclusions.

Throughput values are deliberately never asserted. They are not portable across rigs, and the failure mode that matters is a healthy status on an unhealthy run.

The fixture documents the scrape contract by construction — it emits only what the script actually reads, so an accidental dependency on some other log line fails the suite rather than working by luck.

Notes

  • test-locale-utf8 caught the missing PYTHONUTF8 export in both suites before this PR opened — exactly its job.
  • The mocked suite's EXIT trap needed a bracketed process pattern: the unbracketed form matches the killing command's own command line, self-kills with exit 144, and leaves the fixture it was meant to reap still running. Observed, then fixed.
  • Tier 2 (short real-GPU run) is still to come and will stay out of the default scripts/tests/*.sh sweep so the suite remains fast.

Tests

test-offload-matrix ✅ · test-offload-matrix-mocked ✅ · test-locale-utf8 ✅ (93 scripts) · test-artifact-inventory ✅. Scoped change — no registry, compose or profile touched.

The harness produces numbers that decide serving configs, so its failure mode is
a plausible WRONG number, not a crash. Six defects of exactly that shape shipped
during its development and were caught by luck (#824). These eight checks guard
them, run in ~1.2 s, and need no server, no GPU and no model.

  1 syntax, both halves
  2 MODEL is mandatory, refusal is actionable
  3 COLUMN PARITY -- header width == emit_row values + status, and the width must
    be derived from $HDR. Guards the printf that carried 32 specifiers for 33
    arguments: bash re-ran the format for the surplus arg, so every arm wrote a
    short row PLUS a junk status-only row.
  4 STATUS-ENUM PARITY, sweep <-> renderer. This one has already caught real
    drift: CACHE_DISABLED shipped with no renderer annotation within an hour of
    being added. Mutation-tested -- deleting that annotation reds the suite.
  5 pairing key includes `shape`. Workload shape FLIPS THE SIGN of speculative
    results, so a mispair manufactures a gain that does not exist.
  6 engine-scope guard refuses a non-llama.cpp binary
  7 PLAN=1 enumerates arms and boots nothing
  8 renderer survives a mixed TSV (OK + BOOT_FAIL + CACHE_DISABLED) and lists
    non-OK arms separately instead of folding them into conclusions

Check 7 carries a minimal fake llama-server stub -- it exists to pass the scope
probe in check 6, and it is the seed the Tier 1 mocked-server suite grows from.

Tier 1 (mocked server, ~25 fake arms) and Tier 2 (real short run) still to come;
Tier 2 stays out of the default scripts/tests sweep.
The sweep mkdir's $PWD/offload-matrix-out unless OUT_DIR is set, so running the
Tier 0 suite from the repo root left an artifact directory behind -- including a
results TSV from the refusal-path checks. Every invocation now writes into the
test's temp dir, and check 9 asserts the repo is clean afterwards: a test that
leaves artifacts is a bad test, and this one would have leaked on every CI run.
…suite

The CACHE_DISABLED detector keyed on the presence of a "[moe-cache] enabled:"
line. A PER-DEVICE budget failure still prints that line while one GPU runs with
no pool at all -- measured live 2026-07-30: CUDA0 got no budget, CUDA1 allocated
69 slots, "enabled:" printed, and the arm reported OK. Throughput on such a run
is a blend of a cached and an uncached device and is not comparable with either.

Detection now counts DEVICES THAT ACTUALLY GOT A POOL against the device count:
  0 pooled                -> CACHE_DISABLED (as before)
  0 < pooled < NGPU       -> CACHE_PARTIAL  (new)

Tier 1 suite runs the real sweep end-to-end against a fake llama-server that
emits the exact log lines the script scrapes and serves the two endpoints it
calls -- no GPU, no model, no engine, ~15 s. Five scenarios, each asserting a
status plus the row invariants:

  healthy   -> OK
  partial   -> CACHE_PARTIAL   (the regression guard for the fix above)
  nobudget  -> CACHE_DISABLED, remedy named
  bypass    -> INVALID_BYPASS
  notokens  -> NO_TOKENS

plus a renderer pass proving every failure status is surfaced and separated from
the conclusions. Throughput VALUES are deliberately never asserted -- they are
not portable, and the failure mode that matters is a healthy status on an
unhealthy run.

The fixture documents the scrape contract by construction: it emits only what
the script actually reads, so an accidental dependency on some other log line
fails the suite instead of working by luck.
… shell

The EXIT trap used a process-name pattern that matches the killing command's own
command line. It self-kills, the shell dies with exit 144, the trap never
finishes, and the fixture it was meant to reap survives -- observed exactly that,
with a fake server still bound to a test port after the suite reported ok.

Bracketing the first character of the pattern makes it unable to match itself.
Same class as the rig-wide pgrep/pkill -f footgun.

Sharp edge worth knowing: this also fires from OUTSIDE the suite. Any shell whose
command line happens to contain the unbracketed pattern -- for instance a commit
message describing this very bug -- becomes a match and gets killed by the trap
of a concurrently running test. Hence this message avoids spelling it out.
… callers

Both suites shell out to python3, so the repo's locale invariant applies to them
(#779): python decodes reads, stdout and argv with the LOCALE codec unless UTF-8
mode is on, and a single-byte locale corrupts quietly rather than raising.
test-locale-utf8 caught this before the PR opened, which is what it is for.
@noonghunna

Copy link
Copy Markdown
Owner Author

Superseded by #835, which grew this into the 3-tier suite (static + mocked + tier2-real, both fake-binary fixtures) and folded the partial-cache blind spot into the per-device CACHE_DISABLED fix (#824). Every file here landed there in evolved form. Closing to keep the queue honest — the test coverage this PR pioneered is on master.

@noonghunna noonghunna closed this Aug 1, 2026
@noonghunna
noonghunna deleted the test/offload-matrix-suite branch August 1, 2026 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant