@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / c59a132f96
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 6, 03:15 UTC

[V0 Deprecation] Refactor kv cache from list to element (#37487)

Signed-off-by: yewentao256 <zhyanwentao@126.com>

Wentao Ye committed Mar 23, 2026 at 23:10 UTC c59a132f9674dbc2eadbbe2d72c604dd4651f2b8
27 files changed +70 -85
tests/compile/passes/test_fusion_attn.py
+1 -1
@@ -127,7 +127,7 @@ class AttentionQuantPatternModel(torch.nn.Module):
127 raw_tensor = raw_tensor.view(kv_cache_shape)
128 kv_cache = raw_tensor.permute(*inv_order)
129
130 - self.attn.kv_cache = [kv_cache]
130 + self.attn.kv_cache = kv_cache
131
132 # Build attn metadata
133 self.attn_metadata = self.builder.build(
tests/compile/passes/test_rope_kvcache_fusion.py
+3 -3
@@ -148,7 +148,7 @@ class QKRoPEKVCacheTestModel(torch.nn.Module):
148 raw_tensor = raw_tensor.view(kv_cache_shape)
149 kv_cache = raw_tensor.permute(*inv_order)
150
151 - self.attn.kv_cache = [kv_cache]
151 + self.attn.kv_cache = kv_cache
152
153 # Build attn metadata
154 attn_metadata = self.builder.build(
@@ -295,7 +295,7 @@ def test_rope_kvcache_fusion(
295 }
296 q_unfused, k_unfused, v_unfused, dummy = model(qkv_unfused, pos_unfused)
297 attn_layer = forward_context.no_compile_layers[model.layer_name]
298 - kv_cache_unfused = attn_layer.kv_cache[0]
298 + kv_cache_unfused = attn_layer.kv_cache
299 del dummy
300
301 torch._dynamo.mark_dynamic(qkv, 0)
@@ -309,7 +309,7 @@ def test_rope_kvcache_fusion(
309 }
310 q_fused, k_fused, v_fused, dummy = model_fused(qkv, pos)
311 attn_layer = forward_context.no_compile_layers[model.layer_name]
312 - kv_cache_fused = attn_layer.kv_cache[0]
312 + kv_cache_fused = attn_layer.kv_cache
313 del dummy
314
315 assert fusion_pass.matched_count == 1
tests/v1/e2e/general/test_mamba_prefix_cache.py
+3 -3
@@ -258,8 +258,8 @@ def get_fake_execute_model_fn(original_execute_model_fn: Callable):
258 mamba_kv_cache_dict[
259 num_computed_tokens - num_computed_tokens % BLOCK_SIZE
260 ] = (
261 - kv_cache[0][0][block_id].clone(),
262 - kv_cache[0][1][block_id].clone(),
261 + kv_cache[0][block_id].clone(),
262 + kv_cache[1][block_id].clone(),
263 )
264
265 last_num_computed_tokens = num_computed_tokens
@@ -302,7 +302,7 @@ def get_fake_process_mamba_fn(
302 mamba_layer_name = kv_cache_config.kv_cache_groups[
303 mamba_group_id
304 ].layer_names[0]
305 - mamba_kv_cache = forward_context[mamba_layer_name].kv_cache[0][-1]
305 + mamba_kv_cache = forward_context[mamba_layer_name].kv_cache[-1]
306 mamba_block_table = input_batch.block_table.block_tables[
307 mamba_group_id
308 ].block_table.cpu[0]
tests/v1/worker/test_gpu_model_runner.py
+17 -17
@@ -670,8 +670,8 @@ def test_init_kv_cache_without_kv_sharing(default_vllm_config):
670
671 runner.initialize_kv_cache(kv_cache_config)
672
673 - layer_0_kv = vllm_ctx[layer_0].kv_cache[0]
674 - layer_1_kv = vllm_ctx[layer_1].kv_cache[0]
673 + layer_0_kv = vllm_ctx[layer_0].kv_cache
674 + layer_1_kv = vllm_ctx[layer_1].kv_cache
675 # check layer 1 kv cache does NOT share memory with layer 0
676 assert id(layer_1_kv) != id(layer_0_kv)
677
@@ -740,8 +740,8 @@ def test_init_kv_cache_with_kv_sharing_valid(default_vllm_config):
740 runner.initialize_kv_cache(kv_cache_config)
741 kv_cache_config_after_init = runner.kv_cache_config
742
743 - layer_0_kv = vllm_ctx[layer_0].kv_cache[0]
744 - layer_1_kv = vllm_ctx[layer_1].kv_cache[0]
743 + layer_0_kv = vllm_ctx[layer_0].kv_cache
744 + layer_1_kv = vllm_ctx[layer_1].kv_cache
745 # check layer 1 kv cache shares memory with layer 0
746 assert id(layer_1_kv) == id(layer_0_kv)
747
@@ -864,9 +864,9 @@ def test_hybrid_attention_mamba_tensor_shapes():
864 np.random.shuffle(ind)
865 blocks0, blocks1 = ind[: (num_blocks // 2)], ind[(num_blocks // 2) :]
866
867 - attn_shape = vllm_ctx[layer_0].kv_cache[0].shape
868 - conv_shape = vllm_ctx[layer_2].kv_cache[0][0].shape
869 - ssm_shape = vllm_ctx[layer_2].kv_cache[0][1].shape
867 + attn_shape = vllm_ctx[layer_0].kv_cache.shape
868 + conv_shape = vllm_ctx[layer_2].kv_cache[0].shape
869 + ssm_shape = vllm_ctx[layer_2].kv_cache[1].shape
870
871 # assert we are using FlashInfer
872 assert attn_shape[0] % num_blocks == 0
@@ -905,21 +905,21 @@ def test_hybrid_attention_mamba_tensor_shapes():
905 kernel_blocks_for_attention = kv_blocks_for_attention * block_split_ratio
906
907 for layer in [layer_0, layer_1]:
908 - # attention: kv_cache[0][kernel_block_idx, kv_idx, ...]
908 + # attention: kv_cache[kernel_block_idx, kv_idx, ...]
909 for i, kernel_block in enumerate(kernel_blocks_for_attention):
910 - vllm_ctx[layer].kv_cache[0][kernel_block, :] = attn_blocks_constant[i]
910 + vllm_ctx[layer].kv_cache[kernel_block, :] = attn_blocks_constant[i]
911
912 # fill mamba blocks with constants using kernel block indices
913 for layer in [layer_2, layer_3, layer_4, layer_5]:
914 - # mamba: kv_cache[0][component][kernel_block_idx, ...]
914 + # mamba: kv_cache[component][kernel_block_idx, ...]
915 for i, kv_block in enumerate(kv_blocks_for_mamba):
916 - vllm_ctx[layer].kv_cache[0][0][kv_block, :] = conv_blocks_constant[i]
917 - vllm_ctx[layer].kv_cache[0][1][kv_block, :] = ssm_blocks_constant[i]
916 + vllm_ctx[layer].kv_cache[0][kv_block, :] = conv_blocks_constant[i]
917 + vllm_ctx[layer].kv_cache[1][kv_block, :] = ssm_blocks_constant[i]
918
919 # verify attention and mamba contents are correct
920 for layer in [layer_0, layer_1]:
921 for i, kernel_block in enumerate(kernel_blocks_for_attention):
922 - actual_kv = vllm_ctx[layer].kv_cache[0][kernel_block, :]
922 + actual_kv = vllm_ctx[layer].kv_cache[kernel_block, :]
923 expected = attn_blocks_constant[i]
924
925 # Check K and V separately
@@ -928,8 +928,8 @@ def test_hybrid_attention_mamba_tensor_shapes():
928
929 for layer in [layer_2, layer_3, layer_4, layer_5]:
930 for i, kv_block in enumerate(kv_blocks_for_mamba):
931 - actual_conv = vllm_ctx[layer].kv_cache[0][0][kv_block, :]
932 - actual_ssm = vllm_ctx[layer].kv_cache[0][1][kv_block, :]
931 + actual_conv = vllm_ctx[layer].kv_cache[0][kv_block, :]
932 + actual_ssm = vllm_ctx[layer].kv_cache[1][kv_block, :]
933 expected_conv = conv_blocks_constant[i]
934 expected_ssm = ssm_blocks_constant[i]
935
@@ -938,8 +938,8 @@ def test_hybrid_attention_mamba_tensor_shapes():
938
939 for layer in [layer_2, layer_3, layer_4, layer_5]:
940 for i, kv_block in enumerate(kv_blocks_for_mamba):
941 - actual_conv = vllm_ctx[layer].kv_cache[0][0][kv_block, :]
942 - actual_ssm = vllm_ctx[layer].kv_cache[0][1][kv_block, :]
941 + actual_conv = vllm_ctx[layer].kv_cache[0][kv_block, :]
942 + actual_ssm = vllm_ctx[layer].kv_cache[1][kv_block, :]
943 expected_conv = conv_blocks_constant[i]
944 expected_ssm = ssm_blocks_constant[i]
945 assert torch.equal(actual_conv, expected_conv)
tests/v1/worker/test_utils.py
+10 -10
@@ -23,10 +23,10 @@ def test_bind_kv_cache(default_vllm_config):
23 }
24 runner_kv_caches: list[torch.Tensor] = []
25 bind_kv_cache(kv_cache, ctx, runner_kv_caches)
26 - assert ctx["layers.0.self_attn"].kv_cache[0] is kv_cache["layers.0.self_attn"]
27 - assert ctx["layers.1.self_attn"].kv_cache[0] is kv_cache["layers.1.self_attn"]
28 - assert ctx["layers.2.self_attn"].kv_cache[0] is kv_cache["layers.2.self_attn"]
29 - assert ctx["layers.3.self_attn"].kv_cache[0] is kv_cache["layers.3.self_attn"]
26 + assert ctx["layers.0.self_attn"].kv_cache is kv_cache["layers.0.self_attn"]
27 + assert ctx["layers.1.self_attn"].kv_cache is kv_cache["layers.1.self_attn"]
28 + assert ctx["layers.2.self_attn"].kv_cache is kv_cache["layers.2.self_attn"]
29 + assert ctx["layers.3.self_attn"].kv_cache is kv_cache["layers.3.self_attn"]
30
31 assert runner_kv_caches[0] is kv_cache["layers.0.self_attn"]
32 assert runner_kv_caches[1] is kv_cache["layers.1.self_attn"]
@@ -50,8 +50,8 @@ def test_bind_kv_cache_non_attention(default_vllm_config):
50 runner_kv_caches: list[torch.Tensor] = []
51 bind_kv_cache(kv_cache, ctx, runner_kv_caches)
52
53 - assert ctx["model.layers.20.attn"].kv_cache[0] is kv_cache["model.layers.20.attn"]
54 - assert ctx["model.layers.28.attn"].kv_cache[0] is kv_cache["model.layers.28.attn"]
53 + assert ctx["model.layers.20.attn"].kv_cache is kv_cache["model.layers.20.attn"]
54 + assert ctx["model.layers.28.attn"].kv_cache is kv_cache["model.layers.28.attn"]
55
56 assert runner_kv_caches[0] is kv_cache["model.layers.20.attn"]
57 assert runner_kv_caches[1] is kv_cache["model.layers.28.attn"]
@@ -74,14 +74,14 @@ def test_bind_kv_cache_draft_model(default_vllm_config):
74 runner_kv_caches: list[torch.Tensor] = []
75 bind_kv_cache(kv_cache, ctx, runner_kv_caches)
76
77 - assert ctx["model.layers.0.attn"].kv_cache[0] is kv_cache["model.layers.0.attn"]
78 - assert ctx["model.layers.1.attn"].kv_cache[0] is kv_cache["model.layers.1.attn"]
77 + assert ctx["model.layers.0.attn"].kv_cache is kv_cache["model.layers.0.attn"]
78 + assert ctx["model.layers.1.attn"].kv_cache is kv_cache["model.layers.1.attn"]
79 assert (
80 - ctx["draft_model.layers.0.attn"].kv_cache[0]
80 + ctx["draft_model.layers.0.attn"].kv_cache
81 is kv_cache["draft_model.layers.0.attn"]
82 )
83 assert (
84 - ctx["draft_model.layers.1.attn"].kv_cache[0]
84 + ctx["draft_model.layers.1.attn"].kv_cache
85 is kv_cache["draft_model.layers.1.attn"]
86 )
87
vllm/distributed/kv_transfer/kv_connector/v1/example_connector.py
+2 -4
@@ -181,12 +181,10 @@ class ExampleConnector(KVConnectorBase_V1):
181 # Only process layers that have kv_cache
182 # attribute (attention layers) Skip non-attention
183 # layers like FusedMoE/MLP etc.
184 - kv_cache_attr = getattr(layer, "kv_cache", None)
185 - if kv_cache_attr is None:
184 + kv_cache_layer = getattr(layer, "kv_cache", None)
185 + if kv_cache_layer is None:
186 continue
187
188 - kv_cache_layer = kv_cache_attr[0]
189 -
188 filename = self._generate_filename_debug(
189 layer_name, request.token_ids, request.mm_hashes
190 )
vllm/distributed/kv_transfer/kv_connector/v1/lmcache_integration/vllm_v1_adapter.py
+1 -1
@@ -778,7 +778,7 @@ class LMCacheConnectorV1Impl:
778 continue
779
780 if layer_name not in self.kv_caches:
781 - self.kv_caches[layer_name] = attn_layer.kv_cache[0]
781 + self.kv_caches[layer_name] = attn_layer.kv_cache
782
783 ####################
784 # Worker side APIs
vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_connector.py
+1 -1
@@ -214,7 +214,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
214 if kv_cache is None:
215 continue
216
217 - layer = kv_cache[0]
217 + layer = kv_cache
218
219 kv_cache = self.p2p_nccl_engine.recv_tensor(
220 request.request_id + "#" + layer_name, remote_address
vllm/model_executor/layers/attention/attention.py
+2 -5
@@ -349,10 +349,7 @@ class Attention(nn.Module, AttentionLayerBase):
349 # use a placeholder kv cache tensor during init, which will be replaced
350 # by bind_kv_cache
351 # this variable will not be accessed if use_direct_call is True
352 - self.kv_cache = [
353 - torch.tensor([])
354 - for _ in range(vllm_config.parallel_config.pipeline_parallel_size)
355 - ]
352 + self.kv_cache = torch.tensor([])
353
354 # Initialize KV cache quantization attributes
355 _init_kv_cache_quant(self, quant_config, prefix)
@@ -599,7 +596,7 @@ def get_attention_context(
596 if isinstance(attn_metadata, dict):
597 attn_metadata = attn_metadata[layer_name]
598 attn_layer: Attention | MLAAttention = forward_context.no_compile_layers[layer_name]
602 - kv_cache = attn_layer.kv_cache[0]
599 + kv_cache = attn_layer.kv_cache
600 slot_mapping = forward_context.slot_mapping
601 assert isinstance(slot_mapping, dict), (
602 f"Expected slot_mapping to be a dict, got {type(slot_mapping)}. "
vllm/model_executor/layers/attention/mla_attention.py
+3 -8
@@ -415,12 +415,7 @@ class MLAAttention(nn.Module, AttentionLayerBase):
415 raise ValueError(f"Duplicate layer name: {prefix}")
416 compilation_config.static_forward_context[prefix] = self
417
418 - self.kv_cache = [
419 - torch.tensor([])
420 - for _ in range(
421 - get_current_vllm_config().parallel_config.pipeline_parallel_size
422 - )
423 - ]
418 + self.kv_cache = torch.tensor([])
419
420 self.use_sparse = use_sparse
421
@@ -479,7 +474,7 @@ class MLAAttention(nn.Module, AttentionLayerBase):
474 attn_metadata = forward_context.attn_metadata
475 if isinstance(attn_metadata, dict):
476 attn_metadata = attn_metadata[self.layer_name]
482 - self_kv_cache = self.kv_cache[0]
477 + self_kv_cache = self.kv_cache
478 slot_mapping = forward_context.slot_mapping
479
480 assert isinstance(slot_mapping, dict), (
@@ -939,7 +934,7 @@ def unified_mla_kv_cache_update(
934 return torch.empty(0, device=kv_c_normed.device, dtype=kv_c_normed.dtype)
935
936 attn_layer = forward_context.no_compile_layers[layer_name]
942 - kv_cache = attn_layer.kv_cache[0]
937 + kv_cache = attn_layer.kv_cache
938
939 slot_mapping = forward_context.slot_mapping
940 assert isinstance(slot_mapping, dict), (
vllm/model_executor/layers/attention/static_sink_attention.py
+1 -1
@@ -168,7 +168,7 @@ class StaticSinkAttention(Attention, CustomOp):
168 "sink_key and sink_value have not been prepared"
169 )
170 if not self.sink_populated:
171 - self_kv_cache = self.kv_cache[0]
171 + self_kv_cache = self.kv_cache
172 torch.ops.vllm.maybe_populate_sink(self_kv_cache, self.layer_name)
173
174 return super().forward(query, key, value, output_shape)
vllm/model_executor/layers/kda.py
+1 -1
@@ -306,7 +306,7 @@ class KimiDeltaAttention(nn.Module, MambaBase):
306 non_spec_query_start_loc = attn_metadata.non_spec_query_start_loc
307 non_spec_state_indices_tensor = attn_metadata.non_spec_state_indices_tensor # noqa: E501
308 num_actual_tokens = attn_metadata.num_actual_tokens
309 - constant_caches = self.kv_cache[0]
309 + constant_caches = self.kv_cache
310
311 q_proj_states = q_proj_states[:num_actual_tokens]
312 k_proj_states = k_proj_states[:num_actual_tokens]
vllm/model_executor/layers/mamba/linear_attn.py
+1 -1
@@ -413,7 +413,7 @@ class MiniMaxText01LinearAttention(nn.Module, MambaBase):
413 qkvact = qkvact.view((qkv.shape[0], self.tp_heads, -1))
414 q, k, v = torch.split(qkvact, [self.head_dim] * 3, dim=-1)
415 if attn_metadata is not None:
416 - kv_cache = self.kv_cache[0][0]
416 + kv_cache = self.kv_cache[0]
417 state_indices_tensor = attn_metadata.state_indices_tensor
418 clear_linear_attention_cache_for_new_sequences(
419 kv_cache, state_indices_tensor, attn_metadata
vllm/model_executor/layers/mamba/mamba_mixer.py
+1 -1
@@ -267,7 +267,7 @@ class MambaMixer(MambaBase, PluggableLayer):
267 query_start_loc_p = attn_metadata.query_start_loc_p
268 state_indices_tensor_p = attn_metadata.state_indices_tensor_p
269 state_indices_tensor_d = attn_metadata.state_indices_tensor_d
270 - self_kv_cache = self.kv_cache[0]
270 + self_kv_cache = self.kv_cache
271 conv_state = self_kv_cache[0].transpose(-1, -2)
272 ssm_state = self_kv_cache[1]
273 has_initial_states_p = attn_metadata.has_initial_states_p
vllm/model_executor/layers/mamba/mamba_mixer2.py
+1 -1
@@ -575,7 +575,7 @@ class MambaMixer2(MambaBase, PluggableLayer):
575 assert isinstance(attn_metadata, dict)
576 attn_metadata = attn_metadata[self.prefix]
577 assert isinstance(attn_metadata, Mamba2AttentionMetadata)
578 - self_kv_cache = self.kv_cache[0]
578 + self_kv_cache = self.kv_cache
579 # conv_state = (..., dim, width-1) yet contiguous along 'dim'
580 conv_state = self_kv_cache[0].transpose(-1, -2)
581 ssm_state = self_kv_cache[1]
vllm/model_executor/layers/mamba/short_conv.py
+1 -1
@@ -117,7 +117,7 @@ class ShortConv(MambaBase, CustomOp):
117 assert isinstance(attn_metadata, dict)
118 attn_metadata = attn_metadata[self.prefix]
119 assert isinstance(attn_metadata, ShortConvAttentionMetadata)
120 - self_kv_cache = self.kv_cache[0]
120 + self_kv_cache = self.kv_cache
121 conv_state = self_kv_cache[0].transpose(-1, -2)
122 state_indices_tensor_p = attn_metadata.state_indices_tensor_p
123 state_indices_tensor_d = attn_metadata.state_indices_tensor_d
vllm/model_executor/layers/sparse_attn_indexer.py
+2 -2
@@ -365,7 +365,7 @@ class SparseAttnIndexer(CustomOp):
365 return torch.ops.vllm.sparse_attn_indexer(
366 hidden_states,
367 self.k_cache.prefix,
368 - self.k_cache.kv_cache[0],
368 + self.k_cache.kv_cache,
369 q_fp8,
370 k,
371 weights,
@@ -389,7 +389,7 @@ class SparseAttnIndexer(CustomOp):
389 return torch.ops.vllm.rocm_aiter_sparse_attn_indexer(
390 hidden_states,
391 self.k_cache.prefix,
392 - self.k_cache.kv_cache[0],
392 + self.k_cache.kv_cache,
393 q_fp8,
394 k,
395 weights,
vllm/model_executor/models/bailing_moe_linear.py
+1 -1
@@ -709,7 +709,7 @@ class BailingMoELinearAttention(nn.Module, MambaBase):
709
710 # Get KV cache and state indices
711 if attn_metadata is not None:
712 - kv_cache = self.kv_cache[0][0]
712 + kv_cache = self.kv_cache[0]
713 state_indices_tensor = attn_metadata.state_indices_tensor
714 clear_linear_attention_cache_for_new_sequences(
715 kv_cache, state_indices_tensor, attn_metadata
vllm/model_executor/models/deepseek_v2.py
+1 -1
@@ -586,7 +586,7 @@ class DeepseekV32IndexerCache(torch.nn.Module, AttentionLayerBase):
586 self, head_dim: int, dtype: torch.dtype, prefix: str, cache_config: CacheConfig
587 ):
588 super().__init__()
589 - self.kv_cache = [torch.tensor([])]
589 + self.kv_cache = torch.tensor([])
590 self.head_dim = head_dim
591 self.prefix = prefix
592 self.cache_config = cache_config
vllm/model_executor/models/extract_hidden_states.py
+2 -5
@@ -51,7 +51,7 @@ def unified_kv_cache_update(
51 """
52 forward_context = get_forward_context()
53 attn_layer = forward_context.no_compile_layers[layer_name]
54 - kv_cache = attn_layer.kv_cache[0]
54 + kv_cache = attn_layer.kv_cache
55
56 slot_mapping = forward_context.slot_mapping
57 assert isinstance(slot_mapping, dict), (
@@ -288,10 +288,7 @@ class CacheOnlyAttentionLayer(nn.Module, AttentionLayerBase):
288 )
289
290 # Placeholder KV cache (replaced by bind_kv_cache)
291 - self.kv_cache = [
292 - torch.tensor([])
293 - for _ in range(vllm_config.parallel_config.pipeline_parallel_size)
294 - ]
291 + self.kv_cache = torch.tensor([])
292
293 # Register in compilation context
294 compilation_config = vllm_config.compilation_config
vllm/model_executor/models/olmo_hybrid.py
+1 -1
@@ -428,7 +428,7 @@ class OlmoHybridGatedDeltaNet(nn.Module, MambaBase):
428 non_spec_token_indx = attn_metadata.non_spec_token_indx
429 spec_state_indices_tensor = attn_metadata.spec_state_indices_tensor
430 non_spec_state_indices_tensor = attn_metadata.non_spec_state_indices_tensor
431 - self_kv_cache = self.kv_cache[0]
431 + self_kv_cache = self.kv_cache
432 conv_state = self_kv_cache[0].transpose(-1, -2)
433 ssm_state = self_kv_cache[1]
434 num_actual_tokens = attn_metadata.num_actual_tokens
vllm/model_executor/models/plamo2.py
+1 -1
@@ -262,7 +262,7 @@ class Plamo2MambaMixer(MambaBase, PluggableLayer):
262 assert isinstance(attn_metadata, dict)
263 attn_metadata = attn_metadata[self.prefix]
264 assert isinstance(attn_metadata, Mamba2AttentionMetadata)
265 - self_kv_cache = self.kv_cache[0]
265 + self_kv_cache = self.kv_cache
266 # conv_state = (..., dim, width-1) yet contiguous along 'dim'
267 conv_state = self_kv_cache[0].transpose(-1, -2)
268 ssm_state = self_kv_cache[1]
vllm/model_executor/models/qwen3_next.py
+2 -2
@@ -858,7 +858,7 @@ class Qwen3NextGatedDeltaNet(nn.Module, MambaBase):
858 non_spec_token_indx = attn_metadata.non_spec_token_indx
859 spec_state_indices_tensor = attn_metadata.spec_state_indices_tensor # noqa: E501
860 non_spec_state_indices_tensor = attn_metadata.non_spec_state_indices_tensor # noqa: E501
861 - self_kv_cache = self.kv_cache[0]
861 + self_kv_cache = self.kv_cache
862 conv_state = self_kv_cache[0].transpose(-1, -2)
863 ssm_state = self_kv_cache[1]
864 num_actual_tokens = attn_metadata.num_actual_tokens
@@ -1046,7 +1046,7 @@ class Qwen3NextGatedDeltaNet(nn.Module, MambaBase):
1046 Core attention computation with a packed non-spec decode fast path.
1047 """
1048 non_spec_state_indices_tensor = attn_metadata.non_spec_state_indices_tensor # noqa: E501
1049 - self_kv_cache = self.kv_cache[0]
1049 + self_kv_cache = self.kv_cache
1050 conv_state = self_kv_cache[0].transpose(-1, -2)
1051 ssm_state = self_kv_cache[1]
1052 num_actual_tokens = attn_metadata.num_actual_tokens
vllm/v1/attention/backends/rocm_aiter_fa.py
+3 -7
@@ -481,13 +481,9 @@ class AiterFlashAttentionMetadataBuilder(
481 ):
482 layers = get_layers_from_vllm_config(self.vllm_config, Attention)
483 first_layer_name = [k for k in layers][0]
484 - kv_cache_shape = (
485 - self.vllm_config.compilation_config.static_forward_context[
486 - first_layer_name
487 - ]
488 - .kv_cache[0]
489 - .shape
490 - )
484 + kv_cache_shape = self.vllm_config.compilation_config.static_forward_context[
485 + first_layer_name
486 + ].kv_cache.shape
487 num_blocks = kv_cache_shape[1]
488 self.scale = torch.ones(
489 [num_blocks, self.num_heads_kv, self.block_size],
vllm/v1/worker/gpu_model_runner.py
+4 -1
@@ -5830,7 +5830,10 @@ class GPUModelRunner(
5830
5831 for layer in self.compilation_config.static_forward_context.values():
5832 if hasattr(layer, "kv_cache"):
5833 - layer.kv_cache = []
5833 + kv_cache = layer.kv_cache
5834 + layer.kv_cache = (
5835 + torch.tensor([]) if isinstance(kv_cache, torch.Tensor) else []
5836 + )
5837
5838 gc.collect()
5839 torch.accelerator.empty_cache()
vllm/v1/worker/mamba_utils.py
+1 -1
@@ -119,7 +119,7 @@ def collect_mamba_copy_meta(
119 layer_names = kv_cache_config.kv_cache_groups[mamba_group_id].layer_names
120 for layer_name in layer_names:
121 attention = forward_context[layer_name]
122 - kv_caches: list[torch.Tensor] = attention.kv_cache[0]
122 + kv_caches: list[torch.Tensor] = attention.kv_cache
123 for state, state_copy_func in zip(kv_caches, mamba_state_copy_funcs):
124 copy_spec = state_copy_func(
125 state, block_ids, src_block_idx, accept_token_bias + 1
vllm/v1/worker/utils.py
+3 -4
@@ -136,8 +136,8 @@ class KVBlockZeroer:
136 for layer_name in group.layer_names:
137 if layer_name in runner_only_attn_layers:
138 continue
139 - kv = static_forward_context[layer_name].kv_cache[0]
140 - if isinstance(kv, list):
139 + kv = static_forward_context[layer_name].kv_cache
140 + if not isinstance(kv, torch.Tensor):
141 continue
142 dp = kv.data_ptr()
143 if dp in seen_ptrs:
@@ -510,8 +510,7 @@ def bind_kv_cache(
510
511 # Bind kv_caches to forward context
512 for layer_name, kv_cache in kv_caches.items():
513 - # NOTE: Keep list wrapper for layers that index kv_cache by engine slot.
514 - forward_context[layer_name].kv_cache = [kv_cache]
513 + forward_context[layer_name].kv_cache = kv_cache
514
515
516 def is_residual_scattered_for_sp(