fix: synchronize CP HiCache host eviction semantics
This commit is contained in:
@@ -435,6 +435,11 @@ class HiCacheController:
|
||||
Requirement: no in-flight requests. This call is expected to run on the scheduler
|
||||
thread (control path), not concurrently with prefetch/backup.
|
||||
"""
|
||||
if self.uses_cp_hicache:
|
||||
raise RuntimeError(
|
||||
"CP shared KV HiCache does not support attaching a storage backend at runtime."
|
||||
)
|
||||
|
||||
if self.enable_storage:
|
||||
raise RuntimeError("Storage backend already attached.")
|
||||
|
||||
|
||||
@@ -331,6 +331,12 @@ class HiRadixCache(RadixCache):
|
||||
prefetch/backup paths. Caller must ensure there are no running/queued
|
||||
requests to avoid races.
|
||||
"""
|
||||
if self._uses_cp_hicache:
|
||||
return (
|
||||
False,
|
||||
"CP shared KV HiCache does not support attaching a storage backend at runtime.",
|
||||
)
|
||||
|
||||
# Validate inputs first (no side effects).
|
||||
if hicache_storage_prefetch_policy is not None:
|
||||
allowed = ["best_effort", "wait_complete", "timeout"]
|
||||
@@ -726,8 +732,14 @@ class HiRadixCache(RadixCache):
|
||||
device_indices=node.value,
|
||||
node_id=node.id,
|
||||
)
|
||||
required_host_slots = 0
|
||||
if getattr(result, "metadata", None) is None:
|
||||
required_host_slots = result.required_host_slots
|
||||
self._evict_host_for_physical_slots(
|
||||
required_host_slots,
|
||||
synchronize_across_ranks=getattr(self, "tp_world_size", 1) > 1,
|
||||
)
|
||||
if getattr(result, "metadata", None) is None:
|
||||
self._evict_host_for_physical_slots(result.required_host_slots)
|
||||
result = self.cache_controller.write(
|
||||
device_indices=node.value,
|
||||
node_id=node.id,
|
||||
@@ -741,7 +753,7 @@ class HiRadixCache(RadixCache):
|
||||
self.ongoing_write_through[node.id] = node
|
||||
if not write_back:
|
||||
self.inc_node_lock_ref(node)
|
||||
return len(node.cp_hicache.host_indices)
|
||||
return len(node.value)
|
||||
|
||||
host_indices = self.cache_controller.write(
|
||||
device_indices=node.value,
|
||||
@@ -1084,8 +1096,13 @@ class HiRadixCache(RadixCache):
|
||||
self._update_host_leaf_status(parent)
|
||||
return parent
|
||||
|
||||
def _evict_host_for_physical_slots(self, required_host_slots: int) -> int:
|
||||
if required_host_slots <= 0:
|
||||
def _evict_host_for_physical_slots(
|
||||
self, required_host_slots: int, synchronize_across_ranks: bool = False
|
||||
) -> int:
|
||||
synchronize_across_ranks = (
|
||||
synchronize_across_ranks and getattr(self, "tp_world_size", 1) > 1
|
||||
)
|
||||
if required_host_slots <= 0 and not synchronize_across_ranks:
|
||||
return 0
|
||||
|
||||
leaves = list(self.evictable_host_leaves)
|
||||
@@ -1095,7 +1112,18 @@ class HiRadixCache(RadixCache):
|
||||
heapq.heapify(eviction_heap)
|
||||
|
||||
num_evicted = 0
|
||||
while num_evicted < required_host_slots and len(eviction_heap):
|
||||
|
||||
def all_ranks_done() -> bool:
|
||||
local_done = int(num_evicted >= required_host_slots)
|
||||
if not synchronize_across_ranks:
|
||||
return bool(local_done)
|
||||
done = torch.tensor(local_done, dtype=torch.int, device="cpu")
|
||||
torch.distributed.all_reduce(
|
||||
done, op=torch.distributed.ReduceOp.MIN, group=self.tp_group
|
||||
)
|
||||
return bool(done.item())
|
||||
|
||||
while len(eviction_heap) and not all_ranks_done():
|
||||
_priority, x = heapq.heappop(eviction_heap)
|
||||
if x == self.root_node:
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user