CP HiCache metrics: cover pure-L2 (no L3), lazily create the collector when L2 pooling is on

The collector was created only in _maybe_init_cp_l3 (enable_cp_l3 path), so a pure-L2-pooling
deployment (no L3) got no L2 metrics -- exactly the config under perf investigation. Move creation
into _cp_maybe_collect_metrics: lazily create on first emit, gated on enable_metrics + the shared-L2
allocator existing (L2 pooling on). collect() already handles l3_stats=None, so it reports L2
occupancy/commit/evict with or without L3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-23 09:37:11 +00:00
parent 5163ba7bb9
commit 9dd83bcb88

View File

@@ -1278,19 +1278,8 @@ class HiRadixCache(RadixCache):
"[CP-L3] enabled rank=%d/%d payloads=%s disk_dir=%s",
cp_rank, cp_size, list(accessors), self.cp_l3_store.disk_dir,
)
# CP-HiCache metrics (L2 pooled allocator + L3 store): gated on enable_metrics ALONE (the mainline
# storage metrics are dead under CP). Created once; per-rank via tp_rank. Pushed from check_hicache_events.
if getattr(params, "enable_metrics", False) and self.cp_hicache_metrics is None:
from sglang.srt.observability.metrics_collector import CpHiCacheMetricsCollector
cc = self.cache_controller
labels = {
"tp_rank": cc.tp_rank, "dp_rank": cc.dp_rank,
"pp_rank": cc.pp_rank, "pp_size": cc.pp_size,
}
if self.extra_metric_labels:
labels.update(self.extra_metric_labels)
self.cp_hicache_metrics = CpHiCacheMetricsCollector(labels)
# (CP-HiCache metrics are created lazily in _cp_maybe_collect_metrics, gated on L2 pooling -- so they
# cover PURE-L2-without-L3 too, not just this L3 path.)
@staticmethod
def _cp_l3_single_slab_mmap(allocator, payload_kind: str):
@@ -3841,24 +3830,34 @@ class HiRadixCache(RadixCache):
)
def _cp_maybe_collect_metrics(self) -> None:
"""Push L2 (pooled allocator) + L3 (store) usage to Prometheus, rate-limited (~1s, per-rank wall-clock;
metrics need no rank-uniformity). Off the data path; cheap (occupancy snapshot + queue sizes + counters)."""
collector = self.cp_hicache_metrics
if collector is None:
"""Push L2 (pooled allocator) + L3 (store, if present) usage to Prometheus, rate-limited (~1s, per-rank
wall-clock; metrics need no rank-uniformity). LAZILY creates the collector on first emit, gated on L2
pooling being on (the allocator exists) -- so it covers PURE-L2 (no L3) as well as L2+L3. Off the data
path; cheap (occupancy snapshot + queue sizes + counters)."""
if not self._enable_metrics_flag:
return
allocator = getattr(self.cache_controller, "cp_shared_l2_page_allocator", None)
if allocator is None:
return # L2 pooling not on -> nothing to report
now = time.monotonic()
if now - self._cp_metrics_last_emit < 1.0:
return
self._cp_metrics_last_emit = now
allocator = getattr(self.cache_controller, "cp_shared_l2_page_allocator", None)
l2_occ = (
allocator.occupancy_by_payload()
if allocator is not None and hasattr(allocator, "occupancy_by_payload")
else None
)
l2_stats = allocator.stats() if allocator is not None and hasattr(allocator, "stats") else None
if self.cp_hicache_metrics is None:
from sglang.srt.observability.metrics_collector import CpHiCacheMetricsCollector
cc = self.cache_controller
labels = {
"tp_rank": cc.tp_rank, "dp_rank": cc.dp_rank,
"pp_rank": cc.pp_rank, "pp_size": cc.pp_size,
}
if self.extra_metric_labels:
labels.update(self.extra_metric_labels)
self.cp_hicache_metrics = CpHiCacheMetricsCollector(labels)
l2_occ = allocator.occupancy_by_payload() if hasattr(allocator, "occupancy_by_payload") else None
l2_stats = allocator.stats() if hasattr(allocator, "stats") else None
l3_stats = self.cp_l3_store.stats() if self.cp_l3_store is not None else None
collector.collect(l2_occupancy=l2_occ, l2_stats=l2_stats, l3_stats=l3_stats)
self.cp_hicache_metrics.collect(l2_occupancy=l2_occ, l2_stats=l2_stats, l3_stats=l3_stats)
def _cp_maybe_log_lane_stats(self) -> None:
"""E1 lane-imbalance probe (read-only, measurement only).