Add MambaPool kvcache offloading during retraction (#22493)

This commit is contained in:
hlu1
2026-04-22 08:51:03 +08:00
committed by GitHub
parent 1408d97408
commit 415f64e763
5 changed files with 193 additions and 16 deletions
+8 -2
View File
@@ -1250,13 +1250,19 @@ class Req(ReqDllmMixin):
token_indices = req_to_token_pool.req_to_token[
self.req_pool_idx, : self.seqlen - 1
]
self.kv_cache_cpu = token_to_kv_pool_allocator.get_cpu_copy(token_indices)
# Copies over both the kv cache and mamba state if available
self.kv_cache_cpu = token_to_kv_pool_allocator.get_cpu_copy(
token_indices, mamba_indices=self.mamba_pool_idx
)
def load_kv_cache(self, req_to_token_pool, token_to_kv_pool_allocator):
token_indices = req_to_token_pool.req_to_token[
self.req_pool_idx, : self.seqlen - 1
]
token_to_kv_pool_allocator.load_cpu_copy(self.kv_cache_cpu, token_indices)
# Loads both the kv cache and mamba state if exists
token_to_kv_pool_allocator.load_cpu_copy(
self.kv_cache_cpu, token_indices, mamba_indices=self.mamba_pool_idx
)
del self.kv_cache_cpu
def log_time_stats(self):
+11
View File
@@ -2686,11 +2686,20 @@ class Scheduler(
):
old_available_tokens = self.token_to_kv_pool_allocator.available_size()
old_ratio = self.new_token_ratio
mamba_pool = getattr(self.tree_cache.req_to_token_pool, "mamba_pool", None)
old_mamba_available = (
mamba_pool.available_size() if mamba_pool is not None else None
)
retracted_reqs, new_token_ratio, reqs_to_abort = batch.retract_decode(
self.server_args
)
new_available_tokens = self.token_to_kv_pool_allocator.available_size()
new_token_gained = new_available_tokens - old_available_tokens
mamba_num_gained = (
mamba_pool.available_size() - old_mamba_available
if mamba_pool is not None
else None
)
self.num_retracted_reqs = len(retracted_reqs)
if self.enable_metrics and len(retracted_reqs) > 0:
@@ -2720,6 +2729,8 @@ class Scheduler(
else "Testing retraction. "
)
msg_details = f"#retracted_reqs: {len(retracted_reqs)}, #new_tokens_gained: {new_token_gained}"
if mamba_num_gained is not None:
msg_details += f", #mamba_num_gained: {mamba_num_gained}"
if kv_full_retract_flag:
msg_details += (
f", #new_token_ratio: {old_ratio:.4f} -> {new_token_ratio:.4f}"
+8 -8
View File
@@ -164,11 +164,11 @@ class TokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
else:
self.free_group.append(free_index)
def get_cpu_copy(self, indices):
return self._kvcache.get_cpu_copy(indices)
def get_cpu_copy(self, indices, **kwargs):
return self._kvcache.get_cpu_copy(indices, **kwargs)
def load_cpu_copy(self, kv_cache_cpu, indices):
return self._kvcache.load_cpu_copy(kv_cache_cpu, indices)
def load_cpu_copy(self, kv_cache_cpu, indices, **kwargs):
return self._kvcache.load_cpu_copy(kv_cache_cpu, indices, **kwargs)
def alloc_extend_naive(
@@ -512,8 +512,8 @@ class PagedTokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
self.free_group = []
self.release_pages = torch.empty((0,), dtype=torch.int64, device=self.device)
def get_cpu_copy(self, indices):
return self._kvcache.get_cpu_copy(indices)
def get_cpu_copy(self, indices, **kwargs):
return self._kvcache.get_cpu_copy(indices, **kwargs)
def load_cpu_copy(self, kv_cache_cpu, indices):
return self._kvcache.load_cpu_copy(kv_cache_cpu, indices)
def load_cpu_copy(self, kv_cache_cpu, indices, **kwargs):
return self._kvcache.load_cpu_copy(kv_cache_cpu, indices, **kwargs)
+43 -6
View File
@@ -389,6 +389,28 @@ class MambaPool:
self.copy_from(src_index, dst_index)
return dst_index
def get_cpu_copy(self, indices, **kwargs):
torch.cuda.synchronize()
conv_cpu = [
conv[:, indices].to("cpu", non_blocking=True)
for conv in self.mamba_cache.conv
]
temporal_cpu = self.mamba_cache.temporal[:, indices].to(
"cpu", non_blocking=True
)
torch.cuda.synchronize()
return conv_cpu, temporal_cpu
def load_cpu_copy(self, mamba_cache_cpu, indices, **kwargs):
conv_cpu, temporal_cpu = mamba_cache_cpu
torch.cuda.synchronize()
for i, conv in enumerate(self.mamba_cache.conv):
conv[:, indices] = conv_cpu[i].to(conv.device, non_blocking=True)
self.mamba_cache.temporal[:, indices] = temporal_cpu.to(
self.mamba_cache.temporal.device, non_blocking=True
)
torch.cuda.synchronize()
def get_contiguous_buf_infos(self):
"""
Get buffer info for RDMA registration.
@@ -729,10 +751,10 @@ class KVCache(abc.ABC):
def register_layer_transfer_counter(self, layer_transfer_counter: LayerDoneCounter):
self.layer_transfer_counter = layer_transfer_counter
def get_cpu_copy(self, indices):
def get_cpu_copy(self, indices, **kwargs):
raise NotImplementedError()
def load_cpu_copy(self, kv_cache_cpu, indices):
def load_cpu_copy(self, kv_cache_cpu, indices, **kwargs):
raise NotImplementedError()
def maybe_get_custom_mem_pool(self):
@@ -934,7 +956,7 @@ class MHATokenToKVPool(KVCache):
]
return kv_data_ptrs, kv_data_lens, kv_item_lens
def get_cpu_copy(self, indices):
def get_cpu_copy(self, indices, **kwargs):
torch.cuda.synchronize()
kv_cache_cpu = []
chunk_size = self.cpu_offloading_chunk_size
@@ -952,7 +974,7 @@ class MHATokenToKVPool(KVCache):
torch.cuda.synchronize()
return kv_cache_cpu
def load_cpu_copy(self, kv_cache_cpu, indices):
def load_cpu_copy(self, kv_cache_cpu, indices, **kwargs):
torch.cuda.synchronize()
chunk_size = self.cpu_offloading_chunk_size
for layer_id in range(self.layer_num):
@@ -1418,6 +1440,21 @@ class HybridLinearKVPool(KVCache):
def move_kv_cache(self, tgt_loc: torch.Tensor, src_loc: torch.Tensor):
self.full_kv_pool.move_kv_cache(tgt_loc, src_loc)
def get_cpu_copy(self, indices, mamba_indices=None, **kwargs):
kv_cpu = self.full_kv_pool.get_cpu_copy(indices)
mamba_cpu = (
self.mamba_pool.get_cpu_copy(mamba_indices)
if mamba_indices is not None
else None
)
return kv_cpu, mamba_cpu
def load_cpu_copy(self, cache_cpu, indices, mamba_indices=None, **kwargs):
kv_cpu, mamba_cpu = cache_cpu
self.full_kv_pool.load_cpu_copy(kv_cpu, indices)
if mamba_cpu is not None and mamba_indices is not None:
self.mamba_pool.load_cpu_copy(mamba_cpu, mamba_indices)
def get_v_head_dim(self):
return self.full_kv_pool.get_value_buffer(0).shape[-1]
@@ -1649,7 +1686,7 @@ class MLATokenToKVPool(KVCache):
get_mla_kv_buffer_triton(kv_buffer, loc, cache_k_nope, cache_k_rope)
return cache_k_nope, cache_k_rope
def get_cpu_copy(self, indices):
def get_cpu_copy(self, indices, **kwargs):
torch.cuda.synchronize()
kv_cache_cpu = []
chunk_size = self.cpu_offloading_chunk_size
@@ -1664,7 +1701,7 @@ class MLATokenToKVPool(KVCache):
torch.cuda.synchronize()
return kv_cache_cpu
def load_cpu_copy(self, kv_cache_cpu, indices):
def load_cpu_copy(self, kv_cache_cpu, indices, **kwargs):
torch.cuda.synchronize()
chunk_size = self.cpu_offloading_chunk_size
for layer_id in range(self.layer_num):