Skip to content

fix: use v0.2.5 for benchmark - #814

Merged
zhyncs merged 1 commit into
mainfrom
zhyncs-patch-1
Jul 30, 2024
Merged

zhyncs merged 1 commit into
mainfrom
zhyncs-patch-1

Conversation

@zhyncs

@zhyncs zhyncs commented Jul 30, 2024

Copy link
Copy Markdown
Contributor

Thank you for your contribution, we really appreciate it. The following instructions will help improve your pull request and make it easier to receive feedback. If there are any items you don't understand, don't worry. Just submit the pull request and ask the maintainers for help.

Motivation

Please explain the motivation behind this PR and the goal you aim to achieve with it.

Modification

Briefly describe the changes made in this PR.

Checklist

  1. Ensure pre-commit pre-commit run --all-files or other linting tools are used to fix potential lint issues.
  2. Confirm that modifications are covered by complete unit tests. If not, please add more unit tests for correctness.
  3. Modify documentation as needed, such as docstrings or example tutorials.

@zhyncs
zhyncs merged commit a50c8a1 into main Jul 30, 2024
@zhyncs
zhyncs deleted the zhyncs-patch-1 branch July 30, 2024 02:40
timethink pushed a commit to timethink/sglang that referenced this pull request Mar 9, 2025
litmei pushed a commit to litmei/sglang_litmei that referenced this pull request Jun 16, 2026
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 22, 2026
… cutover

`recover_kv_backing` is the only thing that lifts `KvRowCap`, and its only two
call sites were post-cutover hooks (phase_flip_runtime.py:1818 and :1835). That
is fine while flips commit, and a trap the moment one does not -- a trap that
closes on itself:

  1. a corridor-bounded recovery leaves the ranks unequal (measured on this
     rig, one boot: 210944 / 124928 / 131072 backed rows);
  2. the cap agreement levels the group to the poorest -- correct, since under
     pure PP an id a peer cannot map aborts all three ranks inside
     store_kvcache's bounds assert (phase_flip_boot.py:1264-1278) -- so the
     allocator is capped at 124928 of 465190, 26.8% of the id space;
  3. the capped pool fills, so the group's live floor is 100% of what is left;
  4. the next tp_to_pp flip is DECLINED by that peer floor (sgl-project#812);
  5. no cutover, so no recovery, so the cap is never lifted -- back to 3.

Evidence that step 5 is what actually happened, from the log rather than from
the code: that boot has 27 POOL CENSUS lines = 3 ranks x 9 events, and NOT ONE
is `post-cutover tp_to_pp`. All six return attempts stop at `at-arm`.
`recovered to N of M rows` appears 0 times, `recovery deferred` 0 times,
`recovery failed` 0 times. The pool sat at 26.8% for the life of the process
and a user got an overloaded_error at 21:02:58 against a pool sized 3.7x
larger. So sgl-project#812 and sgl-project#813 are consequences of the cap, not its cause.

Both docstrings already named this outcome. `recover`: "an admission-capacity
loss, which is recoverable ON ANY LATER LEG" -- there was no later leg.
`recover_kv_backing`: "a cap that is never lifted turns dynamic residency into
a permanently smaller pool, which is the one fix the standing rule forbids."

THE FIX IS A LEG, NOT A NEW POLICY. The cap agreement is left exactly as it is:
`cap_proposal` is STRICTLY NON-ALLOCATING on purpose and records why -- the
first metal boot of a growing agreement hit "cuMemCreate failed:
CUDA_ERROR_OUT_OF_MEMORY" on all three ranks, rank 0 driven to 3 MiB free
(kv_backing_relief.py:2710-2745, 2026-08-13). That door stays shut. The design
already assigns growing to exactly one owner, `recover`; it simply had nowhere
to run. This adds the missing call at the abandon exit, where nothing moved and
no seam is owed the memory.

Safety, and none of it is new: `recover`'s bound is intrinsic to the function
(kv_backing_relief.py:2503-2505) -- a fresh per-rank mem_get_info at call time
minus this card's own corridor law, deferring without committing a byte when
`rows <= was`. A new call site inherits exactly what the two post-cutover sites
rely on. The grow stays rank-local and corridor-bounded; the levelling stays
collective and non-allocating.

Collective safety: the helper enters a collective, so it may only be called
where every rank arrives. Its one call site is the group-unanimous abandon exit
in `_execute`, downstream of `reduced_fit = self._collective_min(payload)`
(phase_flip_runtime.py:7381) -- a MIN reduction bit-identical on every rank,
with no `return` and no `raise` anywhere between it and the exit (checked by
reading every statement in that window). Without a channel the helper is a
no-op, matching `recover_kv_backing` on single-rank shapes. It never raises: an
abandon is already the unhappy path and must not become a dead rank.

Tests: test/registered/unit/managers/test_recover_on_abandon_814.py, new,
5 cases, hermetic (CUDA_VISIBLE_DEVICES=""). Three mutants, each killed by its
own dedicated case:
  * single-rank guard removed -> test_without_a_channel_it_is_a_no_op
  * reduce_fn dropped on the delegate -> test_it_delegates_through_the_group_channel
  * logs on every abandon instead of only a real one ->
    test_a_zero_row_recovery_logs_nothing (abandons come in floods; 47 in a
    row were measured)

Regression: 730 passed across the flip/kv-backing/seam/census/evict suites.
3 failures in test_evict_rung_floor_invariant_717.py
("'KvBackingRelief' object has no attribute '_buffers'") are PRE-EXISTING --
measured, not claimed: the identical three fail with the identical error on the
base commit 587e4c2. ruff clean, black clean.

Metal, D1 half of this branch (boot_814_arm2_0822_2146.log): the census now
reads `withheld=330770 unaccounted=122` where it read `unaccounted=340384`,
and 122 is the known irreducible mamba artefact. This commit is the half that
returns the capacity rather than merely describing it; its metal acceptance
follows on the next boot.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 23, 2026
…t#816, sgl-project#810, sgl-project#806, sgl-project#797, sgl-project#790/sgl-project#777, sgl-project#817/sgl-project#820, sgl-project#818

Merge-checklist duty for the nine stages on this branch. Entries follow each
section's own house style, and the mechanism text is taken from the commits'
measured evidence rather than restated from the ticket titles.

§3 KV backing relief + the allocator cap -- UPDATED IN PLACE rather than given
a second bullet, because sgl-project#814 and sgl-project#816 are follow-on defects OF the KvRowCap
mechanism that bullet already describes: the census reading the withheld block
as a leak (340262 of 465190 ids), the lift being reachable only from a cutover
(one boot at 26.8% of its id space for the life of the process), and exposure
exceeding the backing (417850 rows over 105413 committed, the device-side
assert in masked_set_kv_buffer_kernel).

§3 HiCache staging write-through ring (sgl-project#810), new bullet, plus its two
companion refusals -- the unbounded-file-tier refusal and the boot preflight
ledger entry, the latter being why 22.01 GB of MHATokenToKVPoolHost across
three PP ranks previously reached the preflight as nothing.

§7 BAR1 deadline + loud abort -- appended the sgl-project#818 peer-liveness half to the
existing narrative: the gate could wait forever on a peer that no longer
exists, and neither Bar1CollectiveStalled (reset by every resolved read) nor
defer_stall_for_building_peer (900 s off a build marker) caught it.

§12 Robustness canon -- three new families: contradictory-flag (sgl-project#806),
read-back-after-construction (sgl-project#797), denylist-of-reasons (sgl-project#817, sgl-project#820).

§18.3 hicache staging sizing (sgl-project#810) -- §18's own rule is that a merge adding a
reusable module adds its entry in the SAME merge, and this module had none.
Records the removal of fits_pinned_host_budget so it is not reintroduced.

§18.6 mamba carry instrument (sgl-project#767, gated by sgl-project#790) and flip break-even N
(sgl-project#777).

No existing entry was contradicted. Checked before writing: none of sgl-project#814,
sgl-project#810, sgl-project#806, sgl-project#772, sgl-project#797, sgl-project#790, sgl-project#777, sgl-project#817, sgl-project#820, sgl-project#818 had a catalog entry, and
the one sgl-project#677 line (§19.2, RESTORE-NEVER-REBUILD) describes a different
mechanism than the sgl-project#677 layout hold, so it is not stale and was left alone.

Gates for the tree this documents (hermetic, CUDA_VISIBLE_DEVICES=""):

  battery test/registered/unit/{managers,planner,server_args,mem_cache}
    baseline integ @ 78d27da       44 failed
    c56d238 (through sgl-project#818)         30 failed, 8452 passed   0 new ids, 14 fixed
    1c4eadb (through sgl-project#816)         30 failed, 8461 passed   0 new ids, same set
  test_barlink_abort_gate_liveness_818.py (outside the battery dirs)  10 passed
  ruff --select=F401,F821,UP037 and codespell: 0 new findings vs the same
    file set on 78d27da (16 ruff / 6 codespell exist identically on base)
  docs-only change; codespell clean on the catalog itself
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 26, 2026
…ated gap and a

stale double-owned reading as a leak, killing all three schedulers on idle

Five on_idle firings (two boots) showed available+evictable+withheld
exceeding total by exactly 22, never a deficit -- the opposite sign from
sgl-project#814/sgl-project#902/sgl-project#832/sgl-project#856, and never previously routed through the sgl-project#822
ownership authority. Decomposition: 21 rows from
_check_full_pool reading TokenToKVPoolAllocator.available_size() (a raw
sum of free_pages+release_pages, allocator/token.py:52-54) instead of the
union read_free_rows() already used by the phase-flip census and the sgl-project#822
audit (kv_row_ownership.py:743-843); 1 row from a single row simultaneously
claimed by the free list and the radix tree, the sgl-project#822 authority's own
EXCLUSIVITY "claimed by multiple" finding, never subtracted before.

Fix, both additive, neither a tolerance/epsilon:
- _check_full_pool now reads available via read_free_rows() when the
  allocator can enumerate; composite/watermark allocators keep
  ps.full_available_size unchanged.
- _check_pool_invariant gained a double_owned term, subtracted, sourced
  from allocator.double_owned_slots (the sgl-project#822 EXCLUSIVITY count).

Two defects found in review of the first cut, both fixed here:
1. The double_owned filter in
   phase_flip_runtime.py::_census_ownership_audit selected violations by
   substring match on Violation.detail ("more than one owner" in
   v.detail) -- prose used as control flow, against Violation's own
   "detail is never load-bearing" contract, the same shape as the
   line_gate substring defect (sgl-project#908). Fixed by giving Violation a
   structural kind field, set to EXCLUSIVITY_DOUBLED or
   EXCLUSIVITY_UNOWNED at its two EXCLUSIVITY construction sites in
   kv_row_ownership.py, and filtering on kind instead of detail text.
2. double_owned_slots is published only at phase-flip census (seam)
   events and read by on_idle at unrelated times; a reading taken before
   authority.retire() drops every claim it was computed from is stale
   past that point. Fixed by clearing double_owned_slots to None (not 0)
   at the exact point _retire_row_id_space calls authority.retire().
   Checked analytically whether staleness alone could mask a genuine
   deficit: it cannot, for any non-negative reading, because double_owned
   is subtracted and can only push total_accounted further below total.
   It can mask an unrelated, coincidentally-equal-sized surplus; that
   residual case is disclosed, not eliminated, and bounded by the
   cutover-clearing fix.

Tests (test/registered/unit/mem_cache/test_pool_invariant_double_owned_912.py,
14 tests, 31 subtests): reconstructs all five measured specimens,
red-first against unfixed code, green after the fix; separate mutants for
the original subtraction, the kind-based filter, and the retire-time
clearing, each shown to fail only its own guard when reverted; a
parametrized check that no non-negative stale double_owned value can turn
a manufactured 100-row deficit into a false pass.

Gate, hermetic (CUDA_VISIBLE_DEVICES=""), attribution proven by rerunning
identical failing node-id lists with these three files restored to HEAD
(git show HEAD:<path>) and diffing failure sets -- both axes' failures are
identical with and without this fix, i.e. pre-existing:
- mem_cache/: 2 failed, 1951 passed, 1658 skipped, 392 subtests passed
  (139.10s). Failures: test_acceptance_emitters_758.py RefillTiming x2,
  RuntimeError: No CUDA GPUs are available.
- managers/: 15 failed, 4631 passed, 18 skipped, 563 subtests passed
  (719.09s). Failures: test_arena_high_water_631.py x7 and
  test_restore_never_rebuild_677.py x4 (RuntimeError: No CUDA GPUs are
  available), test_phase_flip_rotation_wiring_809.py x4 (Exception:
  retry() exceed maximum number of retries) -- all reproduced identically
  against HEAD-restored files.

ruff check and codespell clean on every line touched by this change (both
tools also flag pre-existing issues elsewhere in phase_flip_runtime.py and
invariant_checker.py, outside this diff's hunks, left untouched as out of
scope for sgl-project#912).
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