[Refactor] Encapsulate SWA loc translation inside SWAKVPool with per-batch cache invalidation (#25824)

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cheng Wan
2026-05-20 21:26:32 -07:00
committed by GitHub
co-authored by Claude Sonnet 4.6
parent 90efa9c83f
commit 79b937aefb
18 changed files with 298 additions and 174 deletions
@@ -1057,9 +1057,6 @@ class TritonAttnBackend(AttentionBackend):
prefix_kv_indices = self.forward_metadata.kv_indices
window_start_pos = None
# For SWA layers, mirror SWAKVPool.set_kv_buffer: read from the
# precomputed pool.swa_loc. Translate out_cache_loc to SWA-pool index space
# as a fallback when pool.swa_loc is not pre-populated.
extend_kv_indices = forward_batch.out_cache_loc
pool = forward_batch.token_to_kv_pool
if (
@@ -1068,12 +1065,7 @@ class TritonAttnBackend(AttentionBackend):
and isinstance(pool, SWAKVPool)
and pool.layers_mapping[layer.layer_id][1]
):
if pool.swa_loc is not None:
extend_kv_indices = pool.swa_loc
else:
extend_kv_indices = pool.translate_loc_from_full_to_swa(
extend_kv_indices
)
extend_kv_indices = pool.translate_loc_from_full_to_swa(extend_kv_indices)
# Handle cases where extend_seq_lens or extend_start_loc might not be set
# In speculative decoding, we can infer these from spec_info or compute them
@@ -187,8 +187,6 @@ class TRTLLMHAAttnBackend(FlashInferAttnBackend):
if self.use_sliding_window_kv_pool:
_, is_swa = self._swa_kv_pool.layers_mapping[layer.layer_id]
if is_swa:
if forward_batch.out_cache_loc_swa is not None:
return forward_batch.out_cache_loc_swa
return self._swa_kv_pool.translate_loc_from_full_to_swa(
forward_batch.out_cache_loc
)
@@ -179,16 +179,9 @@ def unified_attention_with_output(
kwargs["sinks"] = sinks
original_out_cache_loc = forward_batch.out_cache_loc
original_out_cache_loc_swa = forward_batch.out_cache_loc_swa
token_to_kv_pool = forward_batch.token_to_kv_pool
original_swa_loc = getattr(token_to_kv_pool, "swa_loc", None)
# Keep the original ForwardBatch object and only narrow cache locations for
# this backend call so model/backend state is still written to the same batch.
forward_batch.out_cache_loc = original_out_cache_loc[:real_num_tokens]
if original_out_cache_loc_swa is not None:
forward_batch.out_cache_loc_swa = original_out_cache_loc_swa[:real_num_tokens]
if hasattr(token_to_kv_pool, "set_swa_loc"):
token_to_kv_pool.set_swa_loc(forward_batch.out_cache_loc_swa)
# Store pre-allocated output for FA backend to write directly into.
# Must slice to real_num_tokens to match the narrowed query shape —
@@ -205,11 +198,6 @@ def unified_attention_with_output(
**kwargs,
)
forward_batch.out_cache_loc = original_out_cache_loc
forward_batch.out_cache_loc_swa = original_out_cache_loc_swa
if original_out_cache_loc_swa is not None and hasattr(
token_to_kv_pool, "set_swa_loc"
):
token_to_kv_pool.set_swa_loc(original_swa_loc)
if ret.data_ptr() != output.data_ptr():
output[:real_num_tokens].view(ret.shape).copy_(ret)
@@ -120,16 +120,9 @@ def unified_linear_attention_with_output(
real_num_tokens = forward_batch.num_token_non_padded_cpu
original_out_cache_loc = forward_batch.out_cache_loc
original_out_cache_loc_swa = forward_batch.out_cache_loc_swa
token_to_kv_pool = forward_batch.token_to_kv_pool
original_swa_loc = getattr(token_to_kv_pool, "swa_loc", None)
# Keep the original ForwardBatch object and only narrow cache locations for
# this backend call so model/backend state is still written to the same batch.
forward_batch.out_cache_loc = original_out_cache_loc[:real_num_tokens]
if original_out_cache_loc_swa is not None:
forward_batch.out_cache_loc_swa = original_out_cache_loc_swa[:real_num_tokens]
if hasattr(token_to_kv_pool, "set_swa_loc"):
token_to_kv_pool.set_swa_loc(forward_batch.out_cache_loc_swa)
ret = forward_batch.attn_backend.forward(
layer=attention_layer,
@@ -139,11 +132,6 @@ def unified_linear_attention_with_output(
b=b[:real_num_tokens],
)
forward_batch.out_cache_loc = original_out_cache_loc
forward_batch.out_cache_loc_swa = original_out_cache_loc_swa
if original_out_cache_loc_swa is not None and hasattr(
token_to_kv_pool, "set_swa_loc"
):
token_to_kv_pool.set_swa_loc(original_swa_loc)
output[:, :real_num_tokens].copy_(ret)
return
@@ -16,6 +16,9 @@ class BaseSWAKVPool(KVCache):
swa_kv_pool: KVCache
def invalidate_loc_cache(self) -> None:
pass
@abc.abstractmethod
def register_mapping(self, full_to_swa_index_mapping: torch.Tensor) -> None:
raise NotImplementedError()
@@ -24,10 +27,6 @@ class BaseSWAKVPool(KVCache):
def translate_loc_from_full_to_swa(self, kv_indices: torch.Tensor) -> torch.Tensor:
raise NotImplementedError()
@abc.abstractmethod
def set_swa_loc(self, loc: torch.Tensor) -> None:
raise NotImplementedError()
@abc.abstractmethod
def get_state_buf_infos(self) -> Tuple[List[int], List[int], List[int]]:
raise NotImplementedError()
@@ -503,13 +503,6 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
return self.full_to_swa_index_mapping[kv_indices].to(torch.int32)
def set_swa_loc(self, loc: torch.Tensor) -> None:
# No-op: SWAKVPool's set_swa_loc precomputes SWA-translated loc once per
# forward batch for set_kv_buffer to read via self.swa_loc. DSV4 has its
# own equivalent cache via `_should_cache_swa + cached_loc` (in
# set_swa_key_buffer_radix_fused), so we ignore main's precomputed loc.
pass
def get_contiguous_buf_infos(self) -> Tuple[List[int], List[int], List[int]]:
data_ptrs: List[int] = []
data_lens: List[int] = []
+32 -16
View File
@@ -55,7 +55,6 @@ class SWAKVPool(BaseSWAKVPool):
self.layer_num = self.full_layer_nums + self.swa_layer_nums
self.start_layer = 0
self.page_size = page_size
self.swa_loc = None
self.layer_transfer_counter = None
kwargs["page_size"] = page_size
@@ -93,6 +92,8 @@ class SWAKVPool(BaseSWAKVPool):
for swa_layer_id, global_layer_id in enumerate(swa_attention_layer_ids):
self.layers_mapping[global_layer_id] = (swa_layer_id, True)
self.full_to_swa_index_mapping: Optional[torch.Tensor] = None
self._cached_swa_loc: Optional[torch.Tensor] = None
self._cached_loc_key: Optional[tuple] = None
k_size, v_size = self.get_kv_size_bytes()
self.mem_usage = (k_size + v_size) / GB
@@ -102,6 +103,11 @@ class SWAKVPool(BaseSWAKVPool):
def register_mapping(self, full_to_swa_index_mapping: torch.Tensor):
self.full_to_swa_index_mapping = full_to_swa_index_mapping
self.invalidate_loc_cache()
def invalidate_loc_cache(self) -> None:
self._cached_swa_loc = None
self._cached_loc_key = None
def register_layer_transfer_counter(self, layer_transfer_counter):
# Wait happens at this wrapper. Inner pools must not wait again.
@@ -159,15 +165,23 @@ class SWAKVPool(BaseSWAKVPool):
else:
return self.full_kv_pool.get_kv_buffer(layer_id_pool)
def set_swa_loc(self, loc: torch.Tensor):
self.swa_loc = loc
def translate_loc_from_full_to_swa(self, kv_indices: torch.Tensor):
def translate_loc_from_full_to_swa(self, kv_indices: torch.Tensor) -> torch.Tensor:
assert self.full_to_swa_index_mapping is not None
# Note: kv_indices could have -1 values (from alloc_extend), which will be mapped to -1
# since the last item of full_to_swa_index_mapping is -1.
return self.full_to_swa_index_mapping[kv_indices].to(torch.int32)
# data_ptr() (not untyped_storage().data_ptr()) encodes the offset, so
# views at different positions within the same storage get distinct keys.
# -1 in kv_indices maps to -1 via the sentinel appended to the mapping.
key = (kv_indices.data_ptr(), kv_indices.numel())
if key != self._cached_loc_key:
if self._cached_loc_key is not None:
logger.warning(
"translate_loc_from_full_to_swa: loc tensor changed mid-forward "
"without invalidate_loc_cache() — possible missing call site"
)
self._cached_swa_loc = self.full_to_swa_index_mapping[kv_indices].to(
torch.int32
)
self._cached_loc_key = key
return self._cached_swa_loc
def set_kv_buffer(
self,
@@ -182,12 +196,7 @@ class SWAKVPool(BaseSWAKVPool):
layer_id = layer.layer_id
layer_id_pool, is_swa_layer = self.layers_mapping[layer_id]
if is_swa_layer:
if self.swa_loc is not None:
loc = self.swa_loc
else:
if self.full_to_swa_index_mapping is not None:
loc = self.translate_loc_from_full_to_swa(loc)
loc = self.translate_loc_from_full_to_swa(loc)
self.swa_kv_pool.set_kv_buffer(
None,
loc,
@@ -372,8 +381,8 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
self.is_not_in_free_group = True
self.free_group = []
self.clear()
self._kvcache = kvcache
self.clear()
self._kvcache.register_mapping(self.full_to_swa_index_mapping)
def available_size(self):
@@ -416,6 +425,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
return self._kvcache.translate_loc_from_full_to_swa(kv_indices)
def alloc(self, need_size: int):
self._kvcache.invalidate_loc_cache()
assert self.page_size == 1
if need_size > self.full_attn_allocator.available_size():
return None
@@ -444,6 +454,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
last_loc: torch.Tensor, # last_loc for full layers
extend_num_tokens: int,
):
self._kvcache.invalidate_loc_cache()
assert self.page_size > 1
num_new_pages = get_num_new_pages(
@@ -496,6 +507,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
extend_num_tokens: int,
swa_tail_len: int,
):
self._kvcache.invalidate_loc_cache()
"""Allocate full KV for the whole extend and SWA KV only for the tail.
This is used by disaggregated decode preallocation: decode receives full
@@ -557,6 +569,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
seq_lens_cpu: torch.Tensor,
last_loc: torch.Tensor, # last_loc for full layers
):
self._kvcache.invalidate_loc_cache()
assert self.page_size > 1
swa_last_loc = self.translate_loc_from_full_to_swa(last_loc)
@@ -604,6 +617,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
if full_indices.numel() == 0:
return
assert full_indices.numel() == swa_indices.numel()
self._kvcache.invalidate_loc_cache()
if _is_npu:
self.full_to_swa_index_mapping[full_indices.to(torch.int64)] = (
swa_indices.to(torch.int64)
@@ -612,6 +626,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
self.full_to_swa_index_mapping[full_indices] = swa_indices
def free_swa(self, free_index: torch.Tensor):
self._kvcache.invalidate_loc_cache()
swa_indices = self.full_to_swa_index_mapping[free_index]
swa_indices = swa_indices[swa_indices > 0]
self.swa_attn_allocator.free(swa_indices)
@@ -629,6 +644,7 @@ class SWATokenToKVPoolAllocator(BaseTokenToKVPoolAllocator):
self.swa_attn_allocator.restore_state(state[1])
def clear(self):
self._kvcache.invalidate_loc_cache()
self.swa_attn_allocator.clear()
self.full_attn_allocator.clear()
# Note: the last item is -1, we don't clear it, see the comment in __init__
@@ -179,11 +179,6 @@ class BreakableCudaGraphRunner:
(self.max_num_tokens,),
dtype=torch.int64 if not is_npu() else torch.int32,
)
out_cache_loc_swa = (
torch.zeros((self.max_num_tokens,), dtype=torch.int64)
if model_runner.is_hybrid_swa
else None
)
positions = torch.zeros((self.max_num_tokens,), dtype=torch.int64)
if self.is_multimodal:
input_embeds = torch.zeros(
@@ -210,7 +205,6 @@ class BreakableCudaGraphRunner:
self.buffers = PrefillInputBuffers(
input_ids=input_ids,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
mamba_track_indices=None,
mamba_track_mask=None,
mamba_track_seqlens=None,
@@ -302,11 +296,6 @@ class BreakableCudaGraphRunner:
token_to_kv_pool=self.model_runner.token_to_kv_pool,
attn_backend=self.model_runner.attn_backend,
out_cache_loc=buffers.out_cache_loc[:num_tokens],
out_cache_loc_swa=(
buffers.out_cache_loc_swa[:num_tokens]
if buffers.out_cache_loc_swa is not None
else None
),
seq_lens_sum=num_tokens,
mamba_track_indices=None,
mamba_track_mask=None,
@@ -400,6 +389,9 @@ class BreakableCudaGraphRunner:
self.model_runner.attn_backend.init_forward_metadata(forward_batch)
def run_once():
# Invalidate SWA loc cache — same fix as in cuda_graph_runner.run_once.
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
return self._run_forward(forward_batch, num_tokens)
for _ in range(2):
@@ -135,7 +135,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
seq_lens: torch.Tensor
seq_lens_cpu: torch.Tensor
out_cache_loc: torch.Tensor
out_cache_loc_swa: Optional[torch.Tensor]
positions: torch.Tensor
mrope_positions: torch.Tensor
num_token_non_padded: torch.Tensor
@@ -169,7 +168,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
cache_loc_dtype: torch.dtype,
enable_mamba_track: bool,
ne_token_table: Optional[torch.Tensor] = None,
is_hybrid_swa: bool = False,
hc_hidden_size: Optional[int] = None,
) -> "DecodeInputBuffers":
with torch.device(device):
@@ -178,11 +176,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
req_pool_indices = torch.zeros((max_bs,), dtype=torch.int64)
seq_lens = torch.full((max_bs,), seq_len_fill_value, dtype=torch.int32)
out_cache_loc = torch.zeros((max_num_token,), dtype=cache_loc_dtype)
out_cache_loc_swa = (
torch.zeros((max_num_token,), dtype=torch.int32)
if is_hybrid_swa
else None
)
positions = torch.zeros((max_num_token,), dtype=torch.int64)
mrope_positions = torch.zeros((3, max_num_token), dtype=torch.int64)
num_token_non_padded = torch.zeros((1,), dtype=torch.int32)
@@ -260,7 +253,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
seq_lens=seq_lens,
seq_lens_cpu=seq_lens_cpu,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
positions=positions,
mrope_positions=mrope_positions,
num_token_non_padded=num_token_non_padded,
@@ -292,12 +284,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
if bs != raw_bs:
self.seq_lens.fill_(seq_len_fill_value)
self.out_cache_loc.zero_()
# Padded SWA indices left over from a previous replay would point
# into real SWA slots, so set_kv_buffer on padded tokens would
# corrupt active requests' KV. Zero the whole buffer so padded
# positions map to the sentinel slot (matches piecewise runner).
if self.out_cache_loc_swa is not None:
self.out_cache_loc_swa.zero_()
if self.mamba_track_indices is not None:
self.mamba_track_indices.zero_()
if self.mamba_track_mask is not None:
@@ -374,14 +360,6 @@ class DecodeInputBuffers(ForwardInputBuffers):
dsts.append(buf[:dim])
srcs.append(src)
# SWA cache location (int32, separate from the int64 batch above).
if (
self.out_cache_loc_swa is not None
and forward_batch.out_cache_loc_swa is not None
):
dsts.append(self.out_cache_loc_swa[:raw_num_token])
srcs.append(forward_batch.out_cache_loc_swa[:raw_num_token])
# Batch all GPU copies, grouped by dtype pair.
_grouped_foreach_copy_(dsts, srcs)
@@ -696,7 +674,6 @@ class CudaGraphRunner:
ne_token_table=(
model_runner.token_table if self.use_ngram_embedding else None
),
is_hybrid_swa=model_runner.is_hybrid_swa,
hc_hidden_size=getattr(
self.model_runner.model_config, "hc_hidden_size", None
),
@@ -1089,6 +1066,11 @@ class CudaGraphRunner:
# Run and capture
def run_once():
# Without this, warmup-1 caches the translation; the capture run gets
# a hit, skips the gather, and replay reuses stale SWA locations.
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
# Clean intermediate result cache for DP attention
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
@@ -1123,15 +1105,6 @@ class CudaGraphRunner:
self.deepep_adapter.capture(is_extend_in_batch=False)
# swa_loc must be set before capture so that set_kv_buffer's
# Python branch (if self.swa_loc is not None) takes the fast path,
# and the graph records GPU ops using this buffer instead of the
# per-layer translate_loc_from_full_to_swa fallback.
if self.buffers.out_cache_loc_swa is not None:
self.model_runner.token_to_kv_pool.set_swa_loc(
self.buffers.out_cache_loc_swa[:num_tokens]
)
for _ in range(2):
self.device_module.synchronize()
self.model_runner.tp_group.barrier()
@@ -296,8 +296,6 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
# The original sequence length without being chunked. Qwen-1M related.
orig_seq_lens: Optional[torch.Tensor] = None
# The indices of output tokens in the token_to_kv_pool_swa
out_cache_loc_swa: Optional[torch.Tensor] = None
# The indices to track mamba state with
mamba_track_indices: Optional[torch.Tensor] = None # shape: [b], int64
# The mask to track mamba state if needed
@@ -655,14 +653,6 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
else:
ret._compute_mrope_positions(model_runner, batch)
# Precompute SWA cache location once for all SWA layers
if model_runner.is_hybrid_swa and ret.out_cache_loc is not None:
ret.out_cache_loc_swa = (
model_runner.token_to_kv_pool_allocator.translate_loc_from_full_to_swa(
ret.out_cache_loc
)
)
# Init lora information
if model_runner.server_args.enable_lora:
# In the non-LoRA overlap loading case, we fetch LoRA adapters into the memory pool
@@ -1015,10 +1005,6 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
)
self.out_cache_loc = self._pad_tensor_to_size(self.out_cache_loc, num_tokens)
if self.out_cache_loc_swa is not None:
self.out_cache_loc_swa = self._pad_tensor_to_size(
self.out_cache_loc_swa, num_tokens
)
if self.encoder_lens is not None:
self.encoder_lens = self._pad_tensor_to_size(self.encoder_lens, bs)
self.positions = self._pad_tensor_to_size(self.positions, num_tokens)
@@ -3250,9 +3250,8 @@ class ModelRunner(ModelRunnerKVCacheMixin):
server_args=self.server_args,
)
# Use precomputed SWA cache location
if forward_batch.out_cache_loc_swa is not None:
self.token_to_kv_pool.set_swa_loc(forward_batch.out_cache_loc_swa)
if self.is_hybrid_swa:
self.token_to_kv_pool.invalidate_loc_cache()
# Hisparse coordinator
forward_batch.hisparse_coordinator = self.hisparse_coordinator
@@ -81,7 +81,6 @@ _is_musa = is_musa()
class PrefillInputBuffers(ForwardInputBuffers):
input_ids: torch.Tensor
out_cache_loc: torch.Tensor
out_cache_loc_swa: Optional[torch.Tensor]
mamba_track_indices: Optional[torch.Tensor]
mamba_track_mask: Optional[torch.Tensor]
mamba_track_seqlens: Optional[torch.Tensor]
@@ -247,11 +246,6 @@ class PiecewiseCudaGraphRunner:
out_cache_loc = torch.zeros(
(self.max_num_tokens,), dtype=self._cache_loc_dtype()
)
out_cache_loc_swa = (
torch.zeros((self.max_num_tokens,), dtype=torch.int32)
if model_runner.is_hybrid_swa
else None
)
mamba_track_indices = (
torch.zeros((self.max_bs,), dtype=torch.int64)
if self.mamba_track_enabled
@@ -291,7 +285,6 @@ class PiecewiseCudaGraphRunner:
self.buffers = PrefillInputBuffers(
input_ids=input_ids,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
mamba_track_indices=mamba_track_indices,
mamba_track_mask=mamba_track_mask,
mamba_track_seqlens=mamba_track_seqlens,
@@ -368,11 +361,6 @@ class PiecewiseCudaGraphRunner:
buffers.mrope_positions[:, :num_tokens] if self.is_multimodal else None
)
out_cache_loc = buffers.out_cache_loc[:num_tokens]
out_cache_loc_swa = (
buffers.out_cache_loc_swa[:num_tokens]
if buffers.out_cache_loc_swa is not None
else None
)
mamba_track_indices = (
buffers.mamba_track_indices[:1]
if buffers.mamba_track_indices is not None
@@ -403,7 +391,6 @@ class PiecewiseCudaGraphRunner:
token_to_kv_pool=self.model_runner.token_to_kv_pool,
attn_backend=self.model_runner.attn_backend,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
seq_lens_sum=num_tokens,
mamba_track_indices=mamba_track_indices,
mamba_track_mask=mamba_track_mask,
@@ -527,11 +514,6 @@ class PiecewiseCudaGraphRunner:
input_embeds = buffers.input_embeds[:num_tokens] if self.is_multimodal else None
out_cache_loc = buffers.out_cache_loc[:num_tokens]
out_cache_loc_swa = (
buffers.out_cache_loc_swa[:num_tokens]
if buffers.out_cache_loc_swa is not None
else None
)
mamba_track_indices = (
buffers.mamba_track_indices[:bs]
if buffers.mamba_track_indices is not None
@@ -576,7 +558,6 @@ class PiecewiseCudaGraphRunner:
token_to_kv_pool=self.model_runner.token_to_kv_pool,
attn_backend=self.model_runner.attn_backend,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
seq_lens_sum=num_tokens,
mamba_track_indices=mamba_track_indices,
mamba_track_mask=mamba_track_mask,
@@ -614,6 +595,10 @@ class PiecewiseCudaGraphRunner:
# Run and capture
def run_once():
# Invalidate SWA loc cache — same fix as in cuda_graph_runner.run_once.
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
# Clean intermediate result cache for DP attention
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
@@ -662,8 +647,6 @@ class PiecewiseCudaGraphRunner:
self.raw_num_tokens = num_tokens
if static_num_tokens != num_tokens:
buffers.out_cache_loc.zero_()
if buffers.out_cache_loc_swa is not None:
buffers.out_cache_loc_swa.zero_()
buffers.input_ids[num_tokens:static_num_tokens].zero_()
buffers.positions[num_tokens:static_num_tokens].zero_()
if self.is_multimodal:
@@ -676,12 +659,6 @@ class PiecewiseCudaGraphRunner:
buffers.input_ids[:num_tokens].copy_(forward_batch.input_ids)
buffers.positions[:num_tokens].copy_(forward_batch.positions)
buffers.out_cache_loc[:num_tokens].copy_(forward_batch.out_cache_loc)
if buffers.out_cache_loc_swa is not None:
buffers.out_cache_loc_swa[: self.raw_num_tokens].copy_(
self.model_runner.token_to_kv_pool_allocator.translate_loc_from_full_to_swa(
forward_batch.out_cache_loc
)
)
if (
buffers.mamba_track_indices is not None
@@ -703,12 +680,6 @@ class PiecewiseCudaGraphRunner:
positions = buffers.positions[:static_num_tokens]
out_cache_loc = buffers.out_cache_loc[:static_num_tokens]
out_cache_loc_swa = (
buffers.out_cache_loc_swa[:static_num_tokens]
if buffers.out_cache_loc_swa is not None
else None
)
mamba_track_indices = (
buffers.mamba_track_indices[:bs]
if buffers.mamba_track_indices is not None
@@ -766,7 +737,6 @@ class PiecewiseCudaGraphRunner:
token_to_kv_pool=self.model_runner.token_to_kv_pool,
attn_backend=self.model_runner.attn_backend,
out_cache_loc=out_cache_loc,
out_cache_loc_swa=out_cache_loc_swa,
seq_lens_sum=forward_batch.seq_lens_sum,
mamba_track_indices=mamba_track_indices,
mamba_track_mask=mamba_track_mask,
@@ -807,9 +777,6 @@ class PiecewiseCudaGraphRunner:
),
)
if out_cache_loc_swa is not None:
self.model_runner.token_to_kv_pool.set_swa_loc(out_cache_loc_swa)
return static_forward_batch
def replay(
@@ -355,6 +355,9 @@ class EAGLEDraftCudaGraphRunner:
# Run and capture
def run_once():
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
# Clean intermediate result cache for DP attention
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
@@ -395,6 +395,10 @@ class EAGLEDraftExtendCudaGraphRunner:
# Run and capture
def run_once():
# model.forward() bypasses _forward_raw(), so invalidate manually.
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
# Clean intermediate result cache for DP attention
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
@@ -288,6 +288,9 @@ class FrozenKVMTPCudaGraphRunner:
)
def run_once():
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
global_dp_buffer_len,
@@ -66,7 +66,6 @@ class MultiLayerEagleDraftExtendInputBuffers(ForwardInputBuffers):
# Sliced from shared parent buffers
input_ids: torch.Tensor
out_cache_loc: torch.Tensor
swa_out_cache_loc: torch.Tensor
positions: torch.Tensor
# Shared from parent
seq_lens: torch.Tensor
@@ -150,9 +149,6 @@ class MultiLayerEagleDraftExtendCudaGraphRunner:
out_cache_loc = cuda_graph_buffers["out_cache_loc"][
offset : offset + self.max_num_token
]
swa_out_cache_loc = cuda_graph_buffers["swa_out_cache_loc"][
offset : offset + self.max_num_token
]
positions = cuda_graph_buffers["positions"][
offset : offset + self.max_num_token
]
@@ -229,7 +225,6 @@ class MultiLayerEagleDraftExtendCudaGraphRunner:
self.buffers = MultiLayerEagleDraftExtendInputBuffers(
input_ids=input_ids,
out_cache_loc=out_cache_loc,
swa_out_cache_loc=swa_out_cache_loc,
positions=positions,
seq_lens=seq_lens,
seq_lens_cpu=seq_lens_cpu,
@@ -424,6 +419,10 @@ class MultiLayerEagleDraftExtendCudaGraphRunner:
# Run and capture
def run_once():
# model.forward() bypasses _forward_raw(), so invalidate manually.
if self.model_runner.is_hybrid_swa:
self.model_runner.token_to_kv_pool.invalidate_loc_cache()
# Clean intermediate result cache for DP attention
forward_batch.dp_local_start_pos = forward_batch.dp_local_num_tokens = None
set_dp_buffer_len(
@@ -494,12 +493,6 @@ class MultiLayerEagleDraftExtendCudaGraphRunner:
forward_batch.req_to_token_pool.req_to_token,
self.eagle_worker.req_to_hidden_states_pool,
)
next_buffers.swa_out_cache_loc.copy_(
self.model_runner.token_to_kv_pool.translate_loc_from_full_to_swa(
next_buffers.out_cache_loc
)
)
forward_batch.out_cache_loc = output_cache_loc_backup
forward_batch.spec_info.hidden_states = hidden_states_backup
return ret
@@ -683,9 +676,6 @@ class MultiLayerEagleMultiStepDraftExtendCudaGraphRunner:
self.cuda_graph_buffers["out_cache_loc"] = torch.ones(
(self.offsets[-1],), dtype=torch.int64
)
self.cuda_graph_buffers["swa_out_cache_loc"] = torch.ones(
(self.offsets[-1],), dtype=torch.int64
)
self.cuda_graph_buffers["positions"] = torch.zeros(
(self.offsets[-1],), dtype=torch.int64
)
@@ -733,7 +723,6 @@ class MultiLayerEagleMultiStepDraftExtendCudaGraphRunner:
self.cuda_graph_buffers["input_ids"].zero_()
self.cuda_graph_buffers["seq_lens"].fill_(self.seq_len_fill_value)
self.cuda_graph_buffers["out_cache_loc"].zero_()
self.cuda_graph_buffers["swa_out_cache_loc"].zero_()
self.cuda_graph_buffers["positions"].zero_()
# `batch_result.accept_lens` is drafts + bonus.
bs = forward_batch.batch_size