Unify memory management across (overlap, non-overlap) x (page>=1) x (spec, non-spec, spec v2) x (retract, finished) (#12224)
This commit is contained in:
@@ -66,6 +66,7 @@ from sglang.srt.mem_cache.common import (
|
||||
alloc_for_decode,
|
||||
alloc_for_extend,
|
||||
evict_from_tree_cache,
|
||||
release_kv_cache,
|
||||
)
|
||||
from sglang.srt.mem_cache.mamba_radix_cache import MambaRadixCache
|
||||
from sglang.srt.mem_cache.memory_pool import ReqToTokenPool
|
||||
@@ -479,6 +480,12 @@ class Req:
|
||||
self.session_id = session_id
|
||||
self.input_embeds = input_embeds
|
||||
|
||||
# For req-level memory management
|
||||
self.kv_committed_len = 0
|
||||
self.kv_allocated_len = 0
|
||||
self.kv_committed_freed = False
|
||||
self.kv_overallocated_freed = False
|
||||
|
||||
# for corss-endoder model
|
||||
self.token_type_ids = token_type_ids
|
||||
|
||||
@@ -693,6 +700,35 @@ class Req:
|
||||
return self.output_ids[: self.finished_len]
|
||||
return self.output_ids
|
||||
|
||||
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)
|
||||
|
||||
def pop_overallocated_kv_cache(self) -> Tuple[int, int]:
|
||||
"""Return the range of over-allocated KV cache and mark them as freed."""
|
||||
|
||||
# NOTE: This function is called when there is over-allocation of KV cache.
|
||||
# Over-allocation: we allocate more KV cache than the committed length.
|
||||
# e.g., speculative decoding may allocate more KV cache than actually used.
|
||||
assert (
|
||||
not self.kv_overallocated_freed
|
||||
), f"Overallocated KV cache already freed, {self.kv_committed_len=}, {self.kv_allocated_len=}"
|
||||
self.kv_overallocated_freed = True
|
||||
return self.kv_committed_len, self.kv_allocated_len
|
||||
|
||||
def add_latency(self, stage: RequestStage):
|
||||
if self.metrics_collector is None:
|
||||
return
|
||||
@@ -918,6 +954,10 @@ class Req:
|
||||
self.is_chunked = 0
|
||||
self.mamba_pool_idx = None
|
||||
self.already_computed = 0
|
||||
self.kv_allocated_len = 0
|
||||
self.kv_committed_len = 0
|
||||
self.kv_committed_freed = False
|
||||
self.kv_overallocated_freed = False
|
||||
|
||||
def offload_kv_cache(self, req_to_token_pool, token_to_kv_pool_allocator):
|
||||
token_indices = req_to_token_pool.req_to_token[
|
||||
@@ -1262,6 +1302,10 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
|
||||
req.req_pool_idx = req_pool_indices[i]
|
||||
assert seq_len - pre_len == req.extend_input_len
|
||||
|
||||
# update req-level memory management fields
|
||||
req.kv_committed_len = seq_len
|
||||
req.kv_allocated_len = seq_len
|
||||
|
||||
# If input_embeds are available, store them
|
||||
if req.input_embeds is not None:
|
||||
# If req.input_embeds is already a list, append its content directly
|
||||
@@ -1536,7 +1580,7 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
|
||||
self.req_to_token_pool, self.token_to_kv_pool_allocator
|
||||
)
|
||||
# TODO (csy): for preempted requests, we may want to insert into the tree
|
||||
self.tree_cache.cache_finished_req(req, is_insert=False)
|
||||
release_kv_cache(req, self.tree_cache, is_insert=False)
|
||||
# NOTE(lsyin): we should use the newly evictable memory instantly.
|
||||
num_tokens = remaing_req_count * envs.SGLANG_RETRACT_DECODE_STEPS.get()
|
||||
evict_from_tree_cache(self.tree_cache, num_tokens)
|
||||
@@ -1614,6 +1658,11 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
|
||||
# Allocate memory
|
||||
self.out_cache_loc = alloc_for_decode(self, token_per_req=1)
|
||||
|
||||
# Update req-level memory management fields
|
||||
for req in self.reqs:
|
||||
req.kv_committed_len += 1
|
||||
req.kv_allocated_len += 1
|
||||
|
||||
# Update seq_lens after allocation
|
||||
if self.enable_overlap:
|
||||
# Do not use in-place operations in the overlap mode
|
||||
|
||||
Reference in New Issue
Block a user