From fb04e7e3c8c51d80ec4c091ed7c34d86a810a081 Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Thu, 8 Jan 2026 02:35:46 -0800 Subject: [PATCH] [Auto Sync] Update schedule_batch.py, common.py, eagle_info... (20260105) (#16519) Co-authored-by: github-actions[bot] Co-authored-by: cctry --- python/sglang/srt/managers/schedule_batch.py | 19 +++++-------------- python/sglang/srt/mem_cache/common.py | 8 ++++++++ python/sglang/srt/speculative/eagle_info.py | 11 +++++------ 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/python/sglang/srt/managers/schedule_batch.py b/python/sglang/srt/managers/schedule_batch.py index d7037b3ed..17ea53769 100644 --- a/python/sglang/srt/managers/schedule_batch.py +++ b/python/sglang/srt/managers/schedule_batch.py @@ -791,20 +791,11 @@ class Req: def pop_committed_kv_cache(self) -> int: """Return the length of committed KV cache and mark them as freed.""" - - # NOTE: This function is called exactly once after the request is finished. - global_server_args = get_global_server_args() - topk = global_server_args.speculative_eagle_topk - - enable_kv_committed_len = topk is None or topk == 1 - if enable_kv_committed_len: - assert ( - not self.kv_committed_freed - ), f"Committed KV cache already freed ({self.kv_committed_len=})" - self.kv_committed_freed = True - return self.kv_committed_len - else: - return len(self.origin_input_ids) + max(len(self.output_ids) - 1, 0) + assert ( + not self.kv_committed_freed + ), f"Committed KV cache already freed ({self.kv_committed_len=})" + self.kv_committed_freed = True + return self.kv_committed_len def pop_overallocated_kv_cache(self) -> Tuple[int, int]: """Return the range of over-allocated KV cache and mark them as freed.""" diff --git a/python/sglang/srt/mem_cache/common.py b/python/sglang/srt/mem_cache/common.py index 12b3937e3..f5b001a88 100644 --- a/python/sglang/srt/mem_cache/common.py +++ b/python/sglang/srt/mem_cache/common.py @@ -484,6 +484,14 @@ def alloc_for_decode(batch: ScheduleBatch, token_per_req: int) -> torch.Tensor: def release_kv_cache(req: Req, tree_cache: BasePrefixCache, is_insert: bool = True): tree_cache.cache_finished_req(req, is_insert=is_insert) + + # MambaRadixCache may alloc mamba state before alloc KV cache + if req.req_pool_idx is None: + assert isinstance( + tree_cache, MambaRadixCache + ), "Only MambaRadixCache can handle abort with prefix cache hit before alloc" + return + start_p, end_p = req.pop_overallocated_kv_cache() global_server_args = get_global_server_args() diff --git a/python/sglang/srt/speculative/eagle_info.py b/python/sglang/srt/speculative/eagle_info.py index 1bf3816e9..e72c9d725 100644 --- a/python/sglang/srt/speculative/eagle_info.py +++ b/python/sglang/srt/speculative/eagle_info.py @@ -394,9 +394,11 @@ class EagleVerifyInput(SpecInput, EagleVerifyInputV2Mixin): # Iterate every accepted token and check if req has finished after append the token # should be checked BEFORE free kv cache slots for i, (req, accept_index_row) in enumerate(zip(batch.reqs, accept_index_cpu)): + num_accepted = 0 for j, idx in enumerate(accept_index_row): if idx == -1: break + num_accepted += 1 id = predict_cpu[idx] req.output_ids.append(id) req.check_finished() @@ -414,6 +416,9 @@ class EagleVerifyInput(SpecInput, EagleVerifyInputV2Mixin): f"{i=}, {req=}\n" f"{accept_index=}\n" f"{predict=}\n" ) raise e + # Update KV cache tracking for the accepted tokens + req.kv_committed_len += num_accepted + req.kv_allocated_len = req.kv_committed_len if not req.finished(): unfinished_index.append(i) if idx == -1: @@ -442,9 +447,6 @@ class EagleVerifyInput(SpecInput, EagleVerifyInputV2Mixin): if page_size == 1: # TODO: boolean array index leads to a device sync. Remove it. token_to_kv_pool_allocator.free(batch.out_cache_loc[evict_mask]) - for i, req in enumerate(batch.reqs): - req.kv_committed_len += accept_length_list[i] + 1 - req.kv_allocated_len = req.kv_committed_len else: if self.topk == 1: # Only evict full empty page. Do not evict partial empty page @@ -456,9 +458,6 @@ class EagleVerifyInput(SpecInput, EagleVerifyInputV2Mixin): next_power_of_2(self.draft_token_num), ) token_to_kv_pool_allocator.free(batch.out_cache_loc[evict_mask]) - for i, req in enumerate(batch.reqs): - req.kv_committed_len += accept_length_list[i] + 1 - req.kv_allocated_len = req.kv_committed_len else: # Shift the accepted tokens to the beginning. # Only evict the last part