Conversation
…#1050) Replace the remaining O(cap) victim-selection scans in the three MoE engines with intrusive doubly-linked recency lists that mirror the authoritative `used` stamps: - olmoe.c: ev-list (resident && !pinned) + pin-list (resident && pinned); victim_pick = ev-head else pin-head else -1; hit path victim_touch O(1); pin flips re-file via victim_refile. COLI_VICTIM_SCAN=1 kill-switch restores the legacy linear scan verbatim. - qwen36.c: same derived change; apply_resident now re-files pinned slots ev->pin; pilot speculation restricted to unpinned victims. - colibri.c (GLM): single ev-list (resident with slab, fresh used stamp); eslot_victim_pick = JustVugg#1034 free-with-slab reuse (counter, O(free)) else ev-head else legacy scan; publish no longer pushes before the fresh used stamp (refile after stamp at all three pilot sites); per-layer heads/tails initialized to -1. - tests/test_olmoe_victim_index.c: 10 categories incl. delayed pin-flip differential vs legacy scan and speculation pin-exclusion. Review round 1 (Sol + Grok, adversarial): 7 structural findings, all fixed and covered by test assertions; no new compiler warnings vs base; victim + cache-index gates + make test (672 tests) all pass.
…g#1050) Wall-clock evidence for the list pick vs the legacy O(cap) scan it replaces: 2M pick+hide+publish cycles at cap=219 on the same state shape — 2.9-6.8 ns/cycle (list) vs 457-462 ns (legacy scan), i.e. roughly 50-150x on the contended cycle, all under g_pilot_mx. bench_olmoe_victim_index follows the bench_dsa_select precedent: build on demand, not a test gate.
… after post-refile bump) Cross-review (deepseek + sol, blind) flagged refile-then-bump in expert_get: the pin insert-scan keyed on the pre-publish stamp while the post-publish bump moved the slot's used without repositioning — the all-pinned fallback could pick a too-recent pinned slot where the legacy scan picked the true min-used. Differential reproduced (list=0/used=99 vs scan=1/used=5). Fix: stamp before refile; differential test added as test 8.
…mbers Sol-r1 L3: the comment claimed list members are never busy, but eslots_acquire (CUDA/CPU issue paths) does not unlink — members can be in-flight. Logic was already safe (busy check + LRU scan fallback); this fixes only the misleading invariant claim.
|
Reviewed carefully, and I am asking you to hold this one. The idea is right and the olmoe work is good, but three things need to close first and one of them is a defect I verified in your own diff. The ordering rule you wrote down is broken at the second site. In The fix is moving one line. What worries me more is that the test did not catch it, and the reason is structural:
That half also looks wrong to me in two ways. And a smaller one: the NULL check on the three new allocations sits one line below the loop that already dereferences them. On the performance case. The microbenchmark's two loops are not equivalent, the list one does pick plus hide plus publish plus stamp and the legacy one only picks. But the real issue is scale: this is a per-miss cost, and a miss is a multi-megabyte disk read. Against the roughly eight milliseconds an expert read takes, 440 nanoseconds is about five thousandths of a percent. There is no end-to-end tok/s number anywhere in the PR, and I do not expect one to be measurable. So the question I would like answered before the rest: what is the end-to-end difference on a real model? If it is not measurable, that is a fine answer and the PR becomes a code-quality change rather than a performance one, which changes how much risk is worth taking in To make it mergeable: move the refile below the stamp in |
…ential test JustVugg JustVugg#1571 review r2: pilot_realload re-filed the slot BEFORE bumping its stamp, the exact inverse of the expert_get order (L2b fix) — pinning could then file a stale-stamped slot to MRU over genuinely newer members. Also fixes a bug the new differential test caught on the FIXED code: a pin->ev flip tail-appended the slot on its OLD stamp, promoting an older resident to MRU and diverging ev-head from the legacy min-used pick. Pin->ev flips now splice by `used` from the head (rare path, pin-budget bound); fresh-publish stays O(1) tail-append. Adds tests/test_olmoe_differential: drives the REAL expert_get and pilot_realload call sites (checkpoint load stubbed) with randomised ops and pin flips, asserting list pick == legacy scan on every step. Verified both ways: fixed tree passes 2x5000 steps; the injected refile-before-stamp bug fails at step 36. Makefile: TEST_RULES auto-discovery picks up the new test (CI runs it).
…2 review 1. NULL-check the ev_head/ev_tail/ecn_freeslab allocations BEFORE the loop that initialises them (they were checked one line too late — a failed calloc dereferenced NULL in the init loop, UB). 2. rss_guard freed a hidden slot's slab without decrementing ecn_freeslab[] (ecache_hide incremented it while the slab was still alive). The drift made the free-with-slab counter grow without bound, eventually routing victims through the slow path and permanently evicting live residents. 3. eslot_victim_pick: a non-negative list head shadowed the legacy growth rule (return an emptied slot while the row's live-slab count is below capacity). Growth (nn < ecap) is the rare path — pay the legacy scan there instead of trusting the list head.
|
All five points addressed on the branch — thank you, this review earned its keep. 1. Ordering rule — fixed (6f4bf70). 2. The structural blind spot — fixed, and it caught more. Honest note: with pin flips active it also failed on my own corrected code at step 1224 — a pin→ev flip tail-appended the slot on its old stamp, promoting an older resident to MRU over genuinely newer ones. Same defect class as the Sol-r1 M3 pin-list finding, on the ev side. Fixed in the same commit: pin→ev flips now splice by 3. colibri.c — split into its own commit (9ef81b7) with its own message, so it is no longer unmentioned. All three defects fixed: NULL checks moved above the initialising loop; 4. Kill switch — 5. Performance framing — accepting the rebrand. You are right about scale: 440 ns against an ~8 ms disk read is ~0.005% per miss, and the bench loops are not equivalent. The honest answer to "what is the end-to-end difference on a real model" is: not measurable, and I am not going to claim otherwise. If you agree, the PR title/body should be rebranded from perf to code-quality (correctness of the LRU contract under pinning), and the risk bar in CI is running on 9ef81b7. The differential test is in TEST_BINS via Makefile auto-discovery, so it runs in CI from now on. |
Summary
Replaces the O(cap) linear scan in the OLMoE expert victim selection with an O(1) intrusive recency list, closing the long-standing #1050 performance issue.
What
qwen36.cgets the same shared plumbing where the expert-ring layout matches (kept minimal to limit blast radius)Verification (local, rebased on current dev, gcc -O3 -Wall -Wextra clean)
tests/test_olmoe_victim_index: ok (222 lines, covers pick order, re-touch recency, eviction tail, cap rollover)tests/bench_olmoe_victim_indexat cap=219, 2M cycles:make testsuite: OK (skipped=123 — env-gated skips, same set as base dev)Notes
Closes #1050