[HiCache] Fix hicache host memory leak by bounding PP-sync work_list (#28916)

This commit is contained in:
ybyang
2026-06-23 16:39:03 +08:00
committed by GitHub
parent 7b1a20344c
commit 349a6af6b8
3 changed files with 70 additions and 20 deletions
+10 -10
View File
@@ -207,18 +207,17 @@ class HiRadixCache(RadixCache):
if not waited and self.tp_world_size > 1:
torch.distributed.barrier(group=self.tp_group)
def _reap_completed_async_work(self):
def _drain_async_work(self):
"""
Poll outstanding async work and reap completed ones.
Block until all outstanding async sends are consumed, then clear.
Must be called in the scheduler thread.
Called at the start of each event round, so work_list holds the sends
accumulated since the last round. This bounds it and applies
backpressure when a downstream PP rank lags. Scheduler thread only.
"""
count = 0
while count < len(self.work_list) and self.work_list[count].is_completed():
count += 1
if count > 0:
logger.debug(f"Reap {count} completed async work")
self.work_list = self.work_list[count:]
for work in self.work_list:
work.wait()
self.work_list.clear()
def _all_reduce(self, data: torch.Tensor, tp_reduce_op: torch.distributed.ReduceOp):
"""
@@ -1279,11 +1278,12 @@ class HiRadixCache(RadixCache):
self.writing_check()
def check_hicache_events(self):
# Reap the previous round's PP-sync sends before issuing new ones.
self._drain_async_work()
self.writing_check()
self.loading_check()
if self.enable_storage:
self.drain_storage_control_queues()
self._reap_completed_async_work()
if self.enable_storage_metrics:
self.storage_metrics_collector.log_storage_metrics(
self.cache_controller.storage_backend.get_stats()
@@ -395,18 +395,17 @@ class UnifiedRadixCache(KVCacheEventMixin, BasePrefixCache):
if not waited and self.tp_world_size > 1:
torch.distributed.barrier(group=self.tp_group)
def _reap_completed_async_work(self):
def _drain_async_work(self):
"""
Poll outstanding async work and reap completed ones.
Block until all outstanding async sends are consumed, then clear.
Must be called in the scheduler thread.
Called at the start of each event round, so work_list holds the sends
accumulated since the last round. This bounds it and applies
backpressure when a downstream PP rank lags. Scheduler thread only.
"""
count = 0
while count < len(self.work_list) and self.work_list[count].is_completed():
count += 1
if count > 0:
logger.debug(f"Reap {count} completed async work")
self.work_list = self.work_list[count:]
for work in self.work_list:
work.wait()
self.work_list.clear()
def _all_reduce(self, data: torch.Tensor, tp_reduce_op: torch.distributed.ReduceOp):
"""
@@ -2463,11 +2462,12 @@ class UnifiedRadixCache(KVCacheEventMixin, BasePrefixCache):
def check_hicache_events(self) -> None:
"""Called per scheduler step to poll async HiCache events."""
# Reap the previous round's PP-sync sends before issuing new ones.
self._drain_async_work()
self.writing_check()
self.loading_check()
if self.enable_storage:
self.drain_storage_control_queues()
self._reap_completed_async_work()
if self.enable_storage_metrics and self.storage_metrics_collector is not None:
self.storage_metrics_collector.log_storage_metrics(
self.cache_controller.storage_backend.get_stats()