From 93fe86477969e2f039e238744bc7c1055ffa92aa Mon Sep 17 00:00:00 2001 From: leavelet Date: Sat, 20 Jun 2026 19:16:44 +0000 Subject: [PATCH] 2b.3 observability: repoint lane-stats occ/used at the shared pool when pooling on When --enable-cp-shared-physical-l2-hicache is on, the lane-stats occ/used_tokens read 0 (they derive from _cp_counts, which the accounting skips for shared-L2 metadata) -- the per-rank gauge is meaningless. Repoint occ/used/cap at the shared pool's per-payload-slab fill (target_kv/draft_kv/index_k) via the new CpSharedL2PageAllocator.occupancy_by_payload(); add occ_by={payload,rank} + occ_labels so the line is self-describing. The real cp_size (owner round-robin period for the hot-prefix skew) is now computed independently of the occ-vector length. Per-rank (flag-off) path unchanged. Read-only; rank-0; next-restart. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../sglang/srt/mem_cache/cp_shared_l2_pool.py | 10 +++++ python/sglang/srt/mem_cache/hiradix_cache.py | 42 ++++++++++++++----- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/python/sglang/srt/mem_cache/cp_shared_l2_pool.py b/python/sglang/srt/mem_cache/cp_shared_l2_pool.py index 236965507..15d0de90b 100644 --- a/python/sglang/srt/mem_cache/cp_shared_l2_pool.py +++ b/python/sglang/srt/mem_cache/cp_shared_l2_pool.py @@ -786,6 +786,16 @@ class CpSharedL2PageAllocator: total = self._payload_capacity(payload_kind) return total - self.free_pages(payload_kind) + def occupancy_by_payload(self) -> dict[str, tuple[int, int]]: + """Per-payload-slab ``(used_pages, capacity_pages)`` in a stable payload + order. For the lane-stats observability probe: the shared pool's REAL fill, + broken down by payload slab (target_kv/draft_kv/index_k). Derived purely + from the replicated free list, so identical on every CP rank.""" + return { + payload: (self.used_pages(payload), self._payload_capacity(payload)) + for payload in sorted(self._free_by_payload) + } + def stats(self) -> dict[str, int]: capacity = { payload: self._payload_capacity(payload) diff --git a/python/sglang/srt/mem_cache/hiradix_cache.py b/python/sglang/srt/mem_cache/hiradix_cache.py index 04d60b8d5..8f13381e5 100644 --- a/python/sglang/srt/mem_cache/hiradix_cache.py +++ b/python/sglang/srt/mem_cache/hiradix_cache.py @@ -3253,13 +3253,35 @@ class HiRadixCache(RadixCache): return self._cp_lane_stats_last_emit = now - snapshot = self._cp_host_capacity_snapshot() - capacity = snapshot.target_capacity - used = snapshot.target_used - cp_size = len(capacity) + # Real cp_size (owner round-robin period for the hot-prefix skew below) -- + # decoupled from the occ-vector length, which is per-payload when pooling. + cp_size = self._cp_hicache_cp_size() + controller = getattr(self, "cache_controller", None) + allocator = ( + getattr(controller, "cp_shared_l2_page_allocator", None) + if controller is not None + else None + ) + if allocator is not None and hasattr(allocator, "occupancy_by_payload"): + # l2 pooling ON: report the shared pool's per-payload-slab fill. The + # per-rank snapshot (_cp_counts -> target_used) is 0 here because the + # accounting skips shared-L2 metadata (_cp_account_*: `not + # _is_cp_shared_l2_metadata`), so the per-rank gauge is meaningless -- + # repoint occ/used/cap at the actual pool. + by_payload = allocator.occupancy_by_payload() + occ_labels = list(by_payload.keys()) + used = [by_payload[p][0] for p in occ_labels] + capacity = [by_payload[p][1] for p in occ_labels] + occ_by = "payload" + else: + snapshot = self._cp_host_capacity_snapshot() + capacity = list(snapshot.target_capacity) + used = list(snapshot.target_used) + occ_labels = [f"lane{i}" for i in range(len(capacity))] + occ_by = "rank" occ = [ (used[i] / capacity[i]) if capacity[i] > 0 else 0.0 - for i in range(cp_size) + for i in range(len(capacity)) ] max_occ = max(occ) if occ else 0.0 min_occ = min(occ) if occ else 0.0 @@ -3300,10 +3322,7 @@ class HiRadixCache(RadixCache): # shared pool tracks its own pages_used/objects_committed/objects_evicted + # load_hits/misses in the replicated CpSharedL2PageAllocator stats. shared_l2_report = None - controller = getattr(self, "cache_controller", None) - if controller is not None and getattr( - controller, "cp_shared_l2_page_allocator", None - ) is not None: + if allocator is not None and controller is not None: report_fn = getattr(controller, "cp_shared_l2_cache_report", None) if report_fn is not None: try: @@ -3312,10 +3331,13 @@ class HiRadixCache(RadixCache): shared_l2_report = None logger.info( - "[CP_HICACHE_LANE_STATS] occ=%s cap_tokens=%s used_tokens=%s max=%.3f " + "[CP_HICACHE_LANE_STATS] occ_by=%s occ=%s occ_labels=%s cap=%s " + "used=%s max=%.3f " "min=%.3f spread=%.3f imbalance=%s hot_prefix_short=%d hot_prefix_long=%d " "skew_token_threshold=%d drops_since_last=%s drops_total=%s shared_l2_pool=%s", + occ_by, [round(x, 3) for x in occ], + occ_labels, list(capacity), list(used), max_occ,