From 8e04f66a7046fa083cda3f5b8e8325632a5af8fd Mon Sep 17 00:00:00 2001 From: Chao Shi Date: Sat, 29 Aug 2026 00:52:53 +0800 Subject: [PATCH] HiCache: avoid unnecessary all-reduce in check_prefetch_progress (#36425) --- .../srt/mem_cache/unified_radix_cache.py | 32 +++++++++++-------- .../test_unified_radix_cache_unittest.py | 4 +-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/python/sglang/srt/mem_cache/unified_radix_cache.py b/python/sglang/srt/mem_cache/unified_radix_cache.py index 9a749956b..e4d39f76d 100644 --- a/python/sglang/srt/mem_cache/unified_radix_cache.py +++ b/python/sglang/srt/mem_cache/unified_radix_cache.py @@ -1792,13 +1792,27 @@ class UnifiedRadixCache(BasePrefixCache): + len(operation.hash_value) * self.prefetch_timeout_per_page ) - def can_terminate_prefetch(self, operation: PrefetchOperation) -> bool: + @rank_consensus(same_results=True) + def _can_terminate_prefetch(self, operation: PrefetchOperation) -> bool: if self.prefetch_stop_policy == "best_effort": return True if self.prefetch_stop_policy == "wait_complete": return False elif self.prefetch_stop_policy == "timeout": - return self._prefetch_timeout_check_linear_func(operation) + # Wall-clock time may differ among ranks, all-reduce is needed to ensure + # all ranks reach the same final result. Otherwise PP/TP ranks will diverge. + # + # For TP, if any rank reaches the timeout, the final result is timeout. + # + # For PP, PP0 makes the decision and other ranks follow PP0's decision. + should_terminate = False + if self.pp_rank == 0: + should_terminate = self._prefetch_timeout_check_linear_func(operation) + should_terminate_tensor = torch.tensor( + int(should_terminate), dtype=torch.int, device="cpu" + ) + self._all_reduce(should_terminate_tensor, torch.distributed.ReduceOp.MAX) + return should_terminate_tensor.item() == 1 else: return True @@ -1809,18 +1823,10 @@ class UnifiedRadixCache(BasePrefixCache): _, _, _, operation, _, _ = self.ongoing_prefetch[req_id] - # Determine whether or not we should terminate this prefetch request. Make all - # ranks agree on the decision. When running with PP, PPn will follow PP0's decision. - should_terminate = False - if self.pp_rank == 0: - should_terminate = operation.is_terminated() or self.can_terminate_prefetch( - operation - ) - should_terminate_tensor = torch.tensor( - int(should_terminate), dtype=torch.int, device="cpu" + # Determine whether or not we should terminate this prefetch request. + should_terminate = operation.is_terminated() or self._can_terminate_prefetch( + operation ) - self._all_reduce(should_terminate_tensor, torch.distributed.ReduceOp.MAX) - should_terminate = should_terminate_tensor.item() == 1 if not should_terminate: return False diff --git a/test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py b/test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py index f37f480cb..6bf7a282d 100644 --- a/test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py +++ b/test/registered/unit/mem_cache/test_unified_radix_cache_unittest.py @@ -7626,7 +7626,7 @@ class TestPrefetchCommitOrdering(CustomTestCase): cache._check_hybrid_prefetch_result.return_value = 8 cache.cache_controller.prefetch_tokens_occupied = 100 cache.prefetch_loaded_tokens_by_reqid = {} - cache.can_terminate_prefetch.return_value = True + cache._can_terminate_prefetch.return_value = True cache.pp_rank = 0 order = mock.MagicMock() @@ -7799,7 +7799,7 @@ class TestUnifiedRadixPrefetchCorruption(CustomTestCase): operation.hash_value = hashes with ( - mock.patch.object(cache, "can_terminate_prefetch", return_value=True), + mock.patch.object(cache, "_can_terminate_prefetch", return_value=True), # Isolate the drop-release branch under test from the hybrid-sync # step: treat the whole fetched prefix as usable so the insert runs. mock.patch.object(