@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 314285d4f2
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 14, 05:30 UTC

[CI] Fix mypy for `vllm/distributed` (#26593)

Signed-off-by: yewentao256 <zhyanwentao@126.com> Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>

Wentao Ye committed Oct 13, 2025 at 16:02 UTC 314285d4f2134111345b4c4cbb583a925db9a91d
14 files changed +122 -65
tools/pre_commit/mypy.py
+1 -1
@@ -26,6 +26,7 @@ import regex as re
26 FILES = [
27 "vllm/*.py",
28 "vllm/assets",
29 + "vllm/distributed",
30 "vllm/entrypoints",
31 "vllm/inputs",
32 "vllm/logging_utils",
@@ -42,7 +43,6 @@ SEPARATE_GROUPS = [
43 "tests",
44 "vllm/attention",
45 "vllm/compilation",
45 - "vllm/distributed",
46 "vllm/engine",
47 "vllm/executor",
48 "vllm/inputs",
vllm/config/kv_transfer.py
+1 -1
@@ -27,7 +27,7 @@ class KVTransferConfig:
27 engine_id: str | None = None
28 """The engine id for KV transfers."""
29
30 - kv_buffer_device: str | None = "cuda"
30 + kv_buffer_device: str = "cuda"
31 """The device used by kv connector to buffer the KV cache. Choices are
32 'cuda' and 'cpu'."""
33
vllm/distributed/device_communicators/all2all.py
+24 -12
@@ -15,9 +15,11 @@ from vllm.utils.flashinfer import has_flashinfer_all2all
15 from .base_device_communicator import All2AllManagerBase, Cache
16
17 if has_flashinfer_all2all():
18 - from flashinfer.comm import Mapping
19 - from flashinfer.comm.mnnvl import MnnvlConfig
20 - from flashinfer.comm.trtllm_alltoall import MnnvlMoe
18 + from flashinfer.comm import Mapping # type: ignore[import-not-found]
19 + from flashinfer.comm.mnnvl import MnnvlConfig # type: ignore[import-not-found]
20 + from flashinfer.comm.trtllm_alltoall import (
21 + MnnvlMoe, # type: ignore[import-not-found]
22 + )
23
24 logger = init_logger(__name__)
25
@@ -65,6 +67,7 @@ class NaiveAll2AllManager(All2AllManagerBase):
67 ) -> tuple[torch.Tensor, torch.Tensor]:
68 sp_size = self.tp_group.world_size if is_sequence_parallel else 1
69 dp_metadata = get_forward_context().dp_metadata
70 + assert dp_metadata is not None
71 cu_tokens_across_sp_cpu = dp_metadata.cu_tokens_across_sp(sp_size)
72
73 hidden_states = self.naive_multicast(
@@ -81,6 +84,7 @@ class NaiveAll2AllManager(All2AllManagerBase):
84 ep_rank = self.rank if is_sequence_parallel else self.dp_rank
85
86 dp_metadata = get_forward_context().dp_metadata
87 + assert dp_metadata is not None
88 sp_size = self.tp_group.world_size if is_sequence_parallel else 1
89 cu_tokens_across_sp_cpu = dp_metadata.cu_tokens_across_sp(sp_size)
90
@@ -113,7 +117,10 @@ class AgRsAll2AllManager(All2AllManagerBase):
117 """
118 Gather hidden_states and router_logits from all dp ranks.
119 """
116 - sizes = get_forward_context().dp_metadata.get_chunk_sizes_across_dp_rank()
120 + dp_metadata = get_forward_context().dp_metadata
121 + assert dp_metadata is not None
122 + sizes = dp_metadata.get_chunk_sizes_across_dp_rank()
123 + assert sizes is not None
124
125 dist_group = get_ep_group() if is_sequence_parallel else get_dp_group()
126 assert sizes[dist_group.rank_in_group] == hidden_states.shape[0]
@@ -130,7 +137,10 @@ class AgRsAll2AllManager(All2AllManagerBase):
137 """
138 Reduce-scatter hidden_states across all dp ranks.
139 """
133 - sizes = get_forward_context().dp_metadata.get_chunk_sizes_across_dp_rank()
140 + dp_metadata = get_forward_context().dp_metadata
141 + assert dp_metadata is not None
142 + sizes = dp_metadata.get_chunk_sizes_across_dp_rank()
143 + assert sizes is not None
144
145 dist_group = get_ep_group() if is_sequence_parallel else get_dp_group()
146 hidden_states = dist_group.reduce_scatterv(hidden_states, dim=0, sizes=sizes)
@@ -155,7 +165,7 @@ class PPLXAll2AllManager(All2AllManagerBase):
165 if self.internode:
166 # inter-node communication needs nvshmem,
167 # intra-node communication uses p2p mapping directly
158 - from pplx_kernels.nvshmem import (
168 + from pplx_kernels.nvshmem import ( # type: ignore[import-not-found]
169 nvshmem_alloc_empty_unique_id,
170 nvshmem_get_unique_id,
171 nvshmem_init,
@@ -182,7 +192,7 @@ class PPLXAll2AllManager(All2AllManagerBase):
192 self.handle_cache = Cache()
193
194 def get_handle(self, kwargs):
185 - import pplx_kernels as pplx
195 + import pplx_kernels as pplx # type: ignore[import-not-found]
196
197 return self.handle_cache.get_or_create(
198 kwargs,
@@ -208,7 +218,9 @@ class PPLXAll2AllManager(All2AllManagerBase):
218 handle.destroy()
219
220 if self.internode:
211 - from pplx_kernels.nvshmem import nvshmem_finalize
221 + from pplx_kernels.nvshmem import (
222 + nvshmem_finalize, # type: ignore[import-not-found]
223 + )
224
225 logger.debug("PPLX NVSHMEM finalize")
226 nvshmem_finalize()
@@ -288,7 +300,7 @@ class DeepEPHTAll2AllManager(DeepEPAll2AllManagerBase):
300 "args are computed in the Manager itself."
301 )
302
291 - import deep_ep
303 + import deep_ep # type: ignore[import-not-found]
304
305 buffer_kwargs = self._make_all2all_kwargs()
306 logger.debug("DeepEP all2all args %s", buffer_kwargs)
@@ -298,7 +310,7 @@ class DeepEPHTAll2AllManager(DeepEPAll2AllManagerBase):
310 return handle
311
312 def set_num_sms(self, num_sms: int):
301 - import deep_ep
313 + import deep_ep # type: ignore[import-not-found]
314
315 # Right now the buffers are sized for only what the kernels were
316 # created with. So we can only reduce the number of SMS used
@@ -332,7 +344,7 @@ class DeepEPLLAll2AllManager(DeepEPAll2AllManagerBase):
344 num_global_experts: Number of experts in the model.
345 num_local_experts: Number of experts in an EP rank.
346 """
335 - import deep_ep
347 + import deep_ep # type: ignore[import-not-found]
348
349 # Defaults for internode and intranode are taken from DeepEP tests.
350 num_nvl_bytes = envs.VLLM_DEEPEP_BUFFER_SIZE_MB * 1024 * 1024
@@ -358,7 +370,7 @@ class DeepEPLLAll2AllManager(DeepEPAll2AllManagerBase):
370 The kwargs for DeepEPLLAll2AllManager is dictated by
371 _make_all2all_kwargs.
372 """
361 - import deep_ep
373 + import deep_ep # type: ignore[import-not-found]
374
375 buffer_kwargs = self._make_all2all_kwargs(**kwargs)
376 logger.debug("DeepEP all2all args %s", buffer_kwargs)
vllm/distributed/device_communicators/custom_all_reduce.py
+12 -7
@@ -2,6 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from contextlib import contextmanager
5 +from typing import cast
6
7 import torch
8 import torch.distributed as dist
@@ -118,15 +119,18 @@ class CustomAllreduce:
119 # now `device` is a `torch.device` object
120 assert isinstance(device, torch.device)
121 self.device = device
121 - device_capability = current_platform.get_device_capability().as_version_str()
122 + device_capability = current_platform.get_device_capability()
123 if (
124 current_platform.is_cuda()
125 and symm_mem_enabled
125 - and device_capability in CUSTOM_ALL_REDUCE_MAX_SIZES
126 + and device_capability is not None
127 ):
127 - max_size = min(
128 - CUSTOM_ALL_REDUCE_MAX_SIZES[device_capability][world_size], max_size
129 - )
128 + device_capability_str = device_capability.as_version_str()
129 + if device_capability_str in CUSTOM_ALL_REDUCE_MAX_SIZES:
130 + max_size = min(
131 + CUSTOM_ALL_REDUCE_MAX_SIZES[device_capability_str][world_size],
132 + max_size,
133 + )
134 cuda_visible_devices = envs.CUDA_VISIBLE_DEVICES
135 if cuda_visible_devices:
136 device_ids = list(map(int, cuda_visible_devices.split(",")))
@@ -213,6 +217,7 @@ class CustomAllreduce:
217 # We cannot directly use `dist.all_gather_object` here
218 # because it is incompatible with `gloo` backend under inference mode.
219 # see https://github.com/pytorch/pytorch/issues/126032 for details.
220 + all_data: list[list[list[int] | None]]
221 all_data = [[None, None] for _ in range(dist.get_world_size(group=self.group))]
222 all_data[self.rank] = [handle, offset]
223 ranks = sorted(dist.get_process_group_ranks(group=self.group))
@@ -221,8 +226,8 @@ class CustomAllreduce:
226 all_data[i], src=rank, group=self.group, device="cpu"
227 )
228 # Unpack list of tuples to tuple of lists.
224 - handles = [d[0] for d in all_data] # type: ignore
225 - offsets = [d[1] for d in all_data] # type: ignore
229 + handles = cast(list[list[int]], [d[0] for d in all_data])
230 + offsets = cast(list[list[int]], [d[1] for d in all_data])
231 ops.register_graph_buffers(self._ptr, handles, offsets)
232
233 def should_custom_ar(self, inp: torch.Tensor):
vllm/distributed/device_communicators/symm_mem.py
+8 -3
@@ -52,9 +52,14 @@ class SymmMemCommunicator:
52 self.device = device
53 self.group = group
54 self.world_size = dist.get_world_size(self.group)
55 - self.device_capability = (
56 - current_platform.get_device_capability().as_version_str()
57 - )
55 + capability = current_platform.get_device_capability()
56 + if capability is None:
57 + logger.warning(
58 + "SymmMemCommunicator: device capability is unknown, "
59 + "communicator is not available."
60 + )
61 + return
62 + self.device_capability = capability.as_version_str()
63 if self.device_capability not in SYMM_MEM_ALL_REDUCE_MAX_SIZES:
64 logger.warning(
65 "SymmMemCommunicator: Device capability %s not supported, "
vllm/distributed/kv_transfer/kv_connector/factory.py
+12 -2
@@ -3,7 +3,7 @@
3
4 import importlib
5 from collections.abc import Callable
6 -from typing import TYPE_CHECKING
6 +from typing import TYPE_CHECKING, cast
7
8 import vllm.envs as envs
9 from vllm.distributed.kv_transfer.kv_connector.base import (
@@ -48,6 +48,8 @@ class KVConnectorFactory:
48 )
49
50 kv_transfer_config = config.kv_transfer_config
51 + if kv_transfer_config is None:
52 + raise ValueError("kv_transfer_config must be set to create a connector")
53 connector_cls = cls.get_connector_class(kv_transfer_config)
54 logger.info(
55 "Creating v1 connector with name: %s and engine_id: %s",
@@ -70,6 +72,8 @@ class KVConnectorFactory:
72 ) -> type[KVConnectorBaseType]:
73 """Get the connector class by name."""
74 connector_name = kv_transfer_config.kv_connector
75 + if connector_name is None:
76 + raise ValueError("Connector name is not set in KVTransferConfig")
77 if connector_name in cls._registry:
78 connector_cls = cls._registry[connector_name]()
79 else:
@@ -77,7 +81,13 @@ class KVConnectorFactory:
81 if connector_module_path is None:
82 raise ValueError(f"Unsupported connector type: {connector_name}")
83 connector_module = importlib.import_module(connector_module_path)
80 - connector_cls = getattr(connector_module, connector_name)
84 + try:
85 + connector_cls = getattr(connector_module, connector_name)
86 + except AttributeError as e:
87 + raise AttributeError(
88 + f"Class {connector_name} not found in {connector_module_path}"
89 + ) from e
90 + connector_cls = cast(type[KVConnectorBaseType], connector_cls)
91 return connector_cls
92
93
vllm/distributed/kv_transfer/kv_connector/utils.py
+7 -7
@@ -151,21 +151,21 @@ class KVOutputAggregator:
151 aggregated_kv_connector_stats = None
152 invalid_block_ids = set[int]()
153 for model_runner_output in outputs:
154 - output = model_runner_output.kv_connector_output
155 - if not output:
154 + kv_output = model_runner_output.kv_connector_output
155 + if not kv_output:
156 continue
157 update_finished_set(
158 - output.finished_sending, self._send_remaining_count, finished_sending
158 + kv_output.finished_sending, self._send_remaining_count, finished_sending
159 )
160 update_finished_set(
161 - output.finished_recving, self._recv_remaining_count, finished_recving
161 + kv_output.finished_recving, self._recv_remaining_count, finished_recving
162 )
163
164 # Aggregate kv_connector_stats from all workers.
165 if aggregated_kv_connector_stats is None:
166 # Use the first worker's kv_connector_stats as accumulator.
167 - aggregated_kv_connector_stats = output.kv_connector_stats
168 - elif kv_connector_stats := output.kv_connector_stats:
167 + aggregated_kv_connector_stats = kv_output.kv_connector_stats
168 + elif kv_connector_stats := kv_output.kv_connector_stats:
169 if aggregated_kv_connector_stats is None:
170 aggregated_kv_connector_stats = kv_connector_stats
171 else:
@@ -176,7 +176,7 @@ class KVOutputAggregator:
176 aggregated_kv_connector_stats.aggregate(kv_connector_stats)
177 )
178
179 - invalid_block_ids |= output.invalid_block_ids
179 + invalid_block_ids |= kv_output.invalid_block_ids
180
181 # select output of the worker specified by output_rank
182 output = outputs[output_rank]
vllm/distributed/kv_transfer/kv_connector/v1/base.py
+4
@@ -95,6 +95,10 @@ class KVConnectorBase_V1(ABC):
95 )
96 self._connector_metadata: KVConnectorMetadata | None = None
97 self._vllm_config = vllm_config
98 + if vllm_config.kv_transfer_config is not None:
99 + self._kv_transfer_config = vllm_config.kv_transfer_config
100 + else:
101 + raise ValueError("kv_transfer_config must be set for KVConnectorBase_V1")
102 self._role = role
103
104 @property
vllm/distributed/kv_transfer/kv_connector/v1/multi_connector.py
+3 -4
@@ -86,13 +86,11 @@ class MultiConnector(KVConnectorBase_V1):
86 super().__init__(vllm_config=vllm_config, role=role)
87 self._connectors: list[KVConnectorBase_V1] = []
88 self._ktc_kv_transfer_config = []
89 - ktcs = vllm_config.kv_transfer_config.kv_connector_extra_config.get(
90 - "connectors"
91 - )
89 + ktcs = self._kv_transfer_config.kv_connector_extra_config.get("connectors")
90 assert ktcs is not None
91 for ktc in ktcs:
92 temp_config = copy.copy(vllm_config)
95 - engine_id = ktc.get("engine_id", vllm_config.kv_transfer_config.engine_id)
93 + engine_id = ktc.get("engine_id", self._kv_transfer_config.engine_id)
94 temp_config.kv_transfer_config = KVTransferConfig(
95 **ktc, engine_id=engine_id
96 )
@@ -296,6 +294,7 @@ class MultiConnector(KVConnectorBase_V1):
294 str: the required KV cache layout. e.g. HND, or NHD.
295 None if the connector does not require a specific layout.
296 """
297 + assert vllm_config.kv_transfer_config is not None
298 ktcs = vllm_config.kv_transfer_config.kv_connector_extra_config.get(
299 "connectors"
300 )
vllm/distributed/kv_transfer/kv_connector/v1/nixl_connector.py
+12 -6
@@ -297,6 +297,7 @@ class NixlConnectorScheduler:
297 + vllm_config.parallel_config.data_parallel_rank
298 * vllm_config.parallel_config.tensor_parallel_size
299 )
300 + assert vllm_config.kv_transfer_config is not None
301 self.use_host_buffer = vllm_config.kv_transfer_config.kv_buffer_device == "cpu"
302 logger.info("Initializing NIXL Scheduler %s", engine_id)
303
@@ -340,7 +341,8 @@ class NixlConnectorScheduler:
341
342 if params is not None and params.get("do_remote_prefill"):
343 # Remote prefill: get all prompt blocks from remote.
343 - count = len(request.prompt_token_ids) - num_computed_tokens
344 + token_ids = request.prompt_token_ids or []
345 + count = len(token_ids) - num_computed_tokens
346 if count > 0:
347 return count, True
348
@@ -521,6 +523,9 @@ class NixlConnectorWorker:
523 self.vllm_config = vllm_config
524 self.block_size = vllm_config.cache_config.block_size
525
526 + if vllm_config.kv_transfer_config is None:
527 + raise ValueError("kv_transfer_config must be set for NixlConnector")
528 +
529 self.nixl_backends = vllm_config.kv_transfer_config.get_from_extra_config(
530 "backends", ["UCX"]
531 )
@@ -577,17 +582,18 @@ class NixlConnectorWorker:
582 self.use_host_buffer = self.kv_buffer_device == "cpu"
583 # support for oot platform which can't register nixl memory
584 # type based on kv_buffer_device
580 - self.nixl_memory_type = current_platform.get_nixl_memory_type()
581 - if self.nixl_memory_type is None:
585 + nixl_memory_type = current_platform.get_nixl_memory_type()
586 + if nixl_memory_type is None:
587 if self.kv_buffer_device == "cuda":
583 - self.nixl_memory_type = "VRAM"
588 + nixl_memory_type = "VRAM"
589 elif self.kv_buffer_device == "cpu":
585 - self.nixl_memory_type = "DRAM"
586 - if self.nixl_memory_type is None:
590 + nixl_memory_type = "DRAM"
591 + if nixl_memory_type is None:
592 raise RuntimeError(
593 f"{self.device_type} with {self.kv_buffer_device} kv_buffer "
594 "is not supported."
595 )
596 + self.nixl_memory_type = nixl_memory_type
597
598 # Note: host xfer buffer ops when use_host_buffer is True
599 self.copy_blocks: CopyBlocksOp | None = None
vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_connector.py
+11 -8
@@ -75,9 +75,8 @@ class P2pNcclConnector(KVConnectorBase_V1):
75 super().__init__(vllm_config=vllm_config, role=role)
76 self._block_size = vllm_config.cache_config.block_size
77 self._requests_need_load: dict[str, Any] = {}
78 - self.config = vllm_config.kv_transfer_config
79 - self.is_producer = self.config.is_kv_producer
80 - self.chunked_prefill: dict[str, Any] = {}
78 + self.is_producer = self._kv_transfer_config.is_kv_producer
79 + self.chunked_prefill: dict[str, tuple[list[int], list[int] | None]] = {}
80
81 self._rank = get_world_group().rank if role == KVConnectorRole.WORKER else 0
82 self._local_rank = (
@@ -87,7 +86,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
86 self.p2p_nccl_engine = (
87 P2pNcclEngine(
88 local_rank=self._local_rank,
90 - config=self.config,
89 + config=self._kv_transfer_config,
90 hostname="",
91 port_offset=self._rank,
92 )
@@ -346,7 +345,8 @@ class P2pNcclConnector(KVConnectorBase_V1):
345 if self.is_producer:
346 return 0, False
347
349 - num_external_tokens = len(request.prompt_token_ids) - 1 - num_computed_tokens
348 + prompt_token_ids = request.prompt_token_ids or []
349 + num_external_tokens = len(prompt_token_ids) - 1 - num_computed_tokens
350
351 if num_external_tokens < 0:
352 num_external_tokens = 0
@@ -387,7 +387,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
387 ]
388 num_tokens = num_scheduled_tokens + new_req.num_computed_tokens
389 # the request's prompt is chunked prefill
390 - if num_tokens < len(new_req.prompt_token_ids):
390 + if num_tokens < len(new_req.prompt_token_ids or []):
391 # 'CachedRequestData' has no attribute 'prompt_token_ids'
392 self.chunked_prefill[new_req.req_id] = (
393 new_req.block_ids[0],
@@ -397,7 +397,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
397 # the request's prompt is not chunked prefill
398 meta.add_request(
399 request_id=new_req.req_id,
400 - token_ids=new_req.prompt_token_ids,
400 + token_ids=new_req.prompt_token_ids or [],
401 block_ids=new_req.block_ids[0],
402 block_size=self._block_size,
403 )
@@ -405,7 +405,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
405 if new_req.req_id in self._requests_need_load:
406 meta.add_request(
407 request_id=new_req.req_id,
408 - token_ids=new_req.prompt_token_ids,
408 + token_ids=new_req.prompt_token_ids or [],
409 block_ids=new_req.block_ids[0],
410 block_size=self._block_size,
411 )
@@ -421,10 +421,12 @@ class P2pNcclConnector(KVConnectorBase_V1):
421 num_scheduled_tokens = (scheduler_output.num_scheduled_tokens)[req_id]
422 num_tokens = num_scheduled_tokens + num_computed_tokens
423 assert req_id in self.chunked_prefill
424 + assert new_block_ids is not None
425 block_ids = new_block_ids[0]
426 if not resumed_from_preemption:
427 block_ids = self.chunked_prefill[req_id][0] + block_ids
428 prompt_token_ids = self.chunked_prefill[req_id][1]
429 + assert prompt_token_ids is not None
430 # the request's prompt is chunked prefill again
431 if num_tokens < len(prompt_token_ids):
432 self.chunked_prefill[req_id] = (block_ids, prompt_token_ids)
@@ -450,6 +452,7 @@ class P2pNcclConnector(KVConnectorBase_V1):
452
453 # NOTE(rob): For resumed req, new_block_ids is all
454 # of the block_ids for the request.
455 + assert new_block_ids is not None
456 block_ids = new_block_ids[0]
457
458 meta.add_request(
vllm/distributed/kv_transfer/kv_connector/v1/shared_storage_connector.py
+25 -14
@@ -90,11 +90,10 @@ class SharedStorageConnector(KVConnectorBase_V1):
90 super().__init__(vllm_config=vllm_config, role=role)
91 self._block_size = vllm_config.cache_config.block_size
92 self._requests_need_load: dict[str, Request] = {}
93 - transfer_config = vllm_config.kv_transfer_config
94 - self._storage_path = transfer_config.get_from_extra_config(
93 + self._storage_path = self._kv_transfer_config.get_from_extra_config(
94 "shared_storage_path", "/tmp"
95 )
97 - logger.info(vllm_config.kv_transfer_config)
96 + logger.info(self._kv_transfer_config)
97 logger.info("Shared storage path is %s", self._storage_path)
98
99 def start_load_kv(self, forward_context: "ForwardContext", **kwargs: Any) -> None:
@@ -277,9 +276,8 @@ class SharedStorageConnector(KVConnectorBase_V1):
276
277 # Now, first num_tokens_to_check tokens are hit, we need to prepare
278 # the metadata for the worker connector to correctly load the KV
280 - num_tokens_to_check = align_to_block_size(
281 - len(request.prompt_token_ids) - 1, self._block_size
282 - )
279 + token_ids = request.prompt_token_ids or []
280 + num_tokens_to_check = align_to_block_size(len(token_ids) - 1, self._block_size)
281
282 return num_tokens_to_check - num_computed_tokens, False
283
@@ -311,13 +309,15 @@ class SharedStorageConnector(KVConnectorBase_V1):
309
310 total_need_load = 0
311 for new_req in scheduler_output.scheduled_new_reqs:
312 + token_ids = new_req.prompt_token_ids or []
313 + mm_hashes = [f.identifier for f in new_req.mm_features]
314 if new_req.req_id in self._requests_need_load:
315 meta.add_request(
316 - token_ids=new_req.prompt_token_ids,
316 + token_ids=token_ids,
317 block_ids=new_req.block_ids[0],
318 block_size=self._block_size,
319 is_store=False,
320 - mm_hashes=[f.identifier for f in new_req.mm_features],
320 + mm_hashes=mm_hashes,
321 )
322 total_need_load += 1
323 else:
@@ -325,13 +325,13 @@ class SharedStorageConnector(KVConnectorBase_V1):
325 # but a single request can have both store and load.
326 # NOTE(rob): for this debug implementation, we only cache
327 # the original prompt tokens.
328 - if not self._found_match_for_request(new_req):
328 + if not self._found_match_for_prompt(token_ids, mm_hashes):
329 meta.add_request(
330 - token_ids=new_req.prompt_token_ids,
330 + token_ids=token_ids,
331 block_ids=new_req.block_ids[0],
332 block_size=self._block_size,
333 is_store=True,
334 - mm_hashes=[f.identifier for f in new_req.mm_features],
334 + mm_hashes=mm_hashes,
335 )
336
337 cached_reqs = scheduler_output.scheduled_cached_reqs
@@ -355,6 +355,7 @@ class SharedStorageConnector(KVConnectorBase_V1):
355
356 # NOTE(rob): For resumed req, new_block_ids is all
357 # of the block_ids for the request.
358 + assert new_block_ids is not None
359 block_ids = new_block_ids[0]
360
361 meta.add_request(
@@ -379,12 +380,22 @@ class SharedStorageConnector(KVConnectorBase_V1):
380 request: "Request",
381 ) -> bool:
382 """Check if the cache is hit for the request."""
383 + return self._found_match_for_prompt(
384 + list(request.prompt_token_ids or []),
385 + [f.identifier for f in request.mm_features],
386 + )
387 +
388 + def _found_match_for_prompt(
389 + self,
390 + prompt_token_ids: list[int],
391 + mm_hashes: list[str],
392 + ) -> bool:
393 num_tokens_to_check = align_to_block_size(
383 - len(request.prompt_token_ids) - 1, self._block_size
394 + len(prompt_token_ids) - 1, self._block_size
395 )
396 foldername = self._generate_foldername_debug(
386 - torch.tensor(request.prompt_token_ids)[:num_tokens_to_check],
387 - [f.identifier for f in request.mm_features],
397 + torch.tensor(prompt_token_ids)[:num_tokens_to_check],
398 + mm_hashes,
399 create_folder=False,
400 )
401 return os.path.exists(foldername)
vllm/distributed/kv_transfer/kv_pipe/mooncake_pipe.py
+1
@@ -236,6 +236,7 @@ class MooncakePipe(KVPipeBase):
236 self.config = config
237 self.local_rank = local_rank
238 self.kv_rank = self.config.kv_rank
239 + assert self.kv_rank is not None
240 if device is None:
241 self.device = self._select_device(self.config.kv_buffer_device)
242 else:
vllm/distributed/kv_transfer/kv_pipe/pynccl_pipe.py
+1
@@ -53,6 +53,7 @@ class PyNcclPipe(KVPipeBase):
53 self.config = config
54 self.local_rank = local_rank
55 self.kv_rank = self.config.kv_rank
56 + assert self.kv_rank is not None
57 self.kv_parallel_size = self.config.kv_parallel_size
58 if device is None:
59 self.device = self._select_device(self.config.kv_buffer_device)