[Fast Start] Use GPU uuid as socket folder identifier (#56669)

Signed-off-by: Isotr0py <Isotr0py@outlook.com>

Isotr0py committed Sep 14, 2026 at 14:28 UTC dbf49dad11e30ec5d464be74b715a9a9e31c2c5a
4 files changed +30 -69
tests/model_executor/model_loader/test_weight_cache.py
+3 -5
@@ -7,6 +7,7 @@ warm restarts (weights mapped from the daemon via CUDA IPC) must both serve
7 identical outputs.
8 """
9
10 +import glob
11 import os
12 import shutil
13 import subprocess
@@ -21,7 +22,6 @@ import pytest
22
23 from vllm import SamplingParams
24 from vllm.assets.image import ImageAsset
24 -from vllm.model_executor.model_loader.weight_cache.protocol import get_socket_path
25 from vllm.platforms import current_platform
26
27 DAEMON_TIMEOUT_S = 600
@@ -79,9 +79,7 @@ class WeightCacheDaemon:
79 # Poll for the socket files rather than a log line: model loading can
80 # pull in JIT compilers that swap the process's stderr and swallow
81 # everything logged afterwards, making log-based readiness flaky.
82 - expected = [
83 - get_socket_path(gpu_id, self.socket_dir) for gpu_id in range(self.tp_size)
84 - ]
82 + pattern = os.path.join(self.socket_dir, "vllm_weight_cache_*.sock")
83 deadline = time.monotonic() + timeout_s
84 while time.monotonic() < deadline:
85 if self._proc.poll() is not None:
@@ -89,7 +87,7 @@ class WeightCacheDaemon:
87 f"Weight cache daemon exited with {self._proc.returncode}:\n"
88 f"{self._logs()}"
89 )
92 - if all(os.path.exists(path) for path in expected):
90 + if len(glob.glob(pattern)) >= self.tp_size:
91 return
92 time.sleep(1.0)
93 raise TimeoutError(
vllm/model_executor/model_loader/weight_cache/daemon.py
+8 -18
@@ -60,6 +60,7 @@ from vllm.distributed import (
60 ensure_model_parallel_initialized,
61 init_distributed_environment,
62 )
63 +from vllm.engine.arg_utils import EngineArgs
64 from vllm.logger import init_logger
65 from vllm.model_executor.model_loader import get_model_loader
66 from vllm.model_executor.model_loader.utils import process_weights_after_loading
@@ -70,13 +71,15 @@ from vllm.model_executor.model_loader.weight_cache.protocol import (
71 check_ipc_platform_support,
72 check_ipc_quant_support,
73 ensure_private_socket_dir,
73 - get_physical_device_id,
74 + get_current_device_uuid,
75 get_socket_path,
76 recv_msg,
77 send_msg,
78 verify_peer_is_owner,
79 )
80 from vllm.platforms import current_platform
81 +from vllm.utils.argparse_utils import FlexibleArgumentParser
82 +from vllm.utils.network_utils import get_distributed_init_method, get_open_port
83 from vllm.utils.torch_utils import set_default_torch_dtype
84
85 logger = init_logger("vllm.model_executor.model_loader.weight_cache.daemon")
@@ -209,7 +212,7 @@ class WeightCacheDaemon:
212 ready_callback: Invoked once the socket is bound and listening,
213 so the launcher can report overall readiness.
214 """
212 - socket_path = self._socket_path()
215 + socket_path = self._socket_path
216 ensure_private_socket_dir(
217 os.path.dirname(socket_path), strict_perms=self.socket_dir is None
218 )
@@ -268,12 +271,9 @@ class WeightCacheDaemon:
271 ) from e
272 return lock_fd
273
274 + @property
275 def _socket_path(self) -> str:
272 - device_index = torch.accelerator.current_device_index()
273 - gpu_id = get_physical_device_id(device_index)
274 - if gpu_id is None:
275 - gpu_id = device_index
276 - return get_socket_path(gpu_id, self.socket_dir)
276 + return get_socket_path(get_current_device_uuid(), self.socket_dir)
277
278 def _handle_connection(self, conn: socket.socket) -> None:
279 request = recv_msg(conn)
@@ -304,7 +304,7 @@ class WeightCacheDaemon:
304 "status": "ok",
305 "entries": self.entries,
306 "aliases": self.aliases,
307 - "gpu_uuid": self._gpu_uuid(),
307 + "gpu_uuid": get_current_device_uuid(),
308 },
309 )
310 logger.info_once(
@@ -322,12 +322,6 @@ class WeightCacheDaemon:
322 logger.info("Weight cache daemon rank %d released cached weights", self.tp_rank)
323 send_msg(conn, {"status": "ok"})
324
325 - def _gpu_uuid(self) -> str:
326 - props = torch.cuda.get_device_properties(
327 - torch.accelerator.current_device_index()
328 - )
329 - return str(props.uuid)
330 -
325
326 def _run_daemon(
327 tp_rank: int,
@@ -359,10 +353,6 @@ def _reject_unsupported_parallelism(parallel_config: ParallelConfig) -> None:
353
354
355 def main() -> None:
362 - from vllm.engine.arg_utils import EngineArgs
363 - from vllm.utils.argparse_utils import FlexibleArgumentParser
364 - from vllm.utils.network_utils import get_distributed_init_method, get_open_port
365 -
356 parser = FlexibleArgumentParser(
357 description="Launch weight cache daemons (one per TP rank)."
358 )
vllm/model_executor/model_loader/weight_cache/ipc_loader.py
+8 -19
@@ -12,6 +12,10 @@ import torch.nn as nn
12
13 from vllm.config import ModelConfig, VllmConfig
14 from vllm.config.load import LoadConfig
15 +from vllm.distributed import (
16 + get_tensor_model_parallel_rank,
17 + get_tensor_model_parallel_world_size,
18 +)
19 from vllm.logger import init_logger
20 from vllm.model_executor.model_loader.base_loader import BaseModelLoader
21 from vllm.model_executor.model_loader.default_loader import DefaultModelLoader
@@ -27,7 +31,7 @@ from vllm.model_executor.model_loader.weight_cache.protocol import (
31 WeightCacheUnavailableError,
32 check_ipc_platform_support,
33 check_ipc_quant_support,
30 - get_physical_device_id,
34 + get_current_device_uuid,
35 get_socket_path,
36 recv_msg,
37 send_msg,
@@ -56,7 +60,7 @@ class IpcModelLoader(BaseModelLoader):
60 Extra config keys (via --model-loader-extra-config):
61
62 - socket_path: explicit daemon socket path. Defaults to a per-GPU path
59 - derived from the physical GPU id.
63 + derived from the physical GPU uuid.
64 - socket_dir: directory containing the daemon sockets.
65 - mode: "zero_copy" (default) or "copy".
66 - fallback: fall back to disk loading when the daemon is unavailable or
@@ -261,11 +265,6 @@ class IpcModelLoader(BaseModelLoader):
265 def _fetch_entries(
266 self, model_config: ModelConfig
267 ) -> tuple[dict[str, TensorEntry], dict[str, str]]:
264 - from vllm.distributed import (
265 - get_tensor_model_parallel_rank,
266 - get_tensor_model_parallel_world_size,
267 - )
268 -
268 cache_config = WeightCacheKey.from_model_config(
269 model_config,
270 tp_size=get_tensor_model_parallel_world_size(),
@@ -317,22 +316,12 @@ class IpcModelLoader(BaseModelLoader):
316 def _resolve_socket_path(self) -> str:
317 if self.socket_path is not None:
318 return self.socket_path
320 - device_index = torch.accelerator.current_device_index()
321 - gpu_id = get_physical_device_id(device_index)
322 - if gpu_id is None:
323 - raise WeightCacheUnavailableError(
324 - "Cannot infer the physical GPU id from CUDA_VISIBLE_DEVICES; "
325 - "pass socket_path via --model-loader-extra-config"
326 - )
327 - return get_socket_path(gpu_id, self.socket_dir)
319 + return get_socket_path(get_current_device_uuid(), self.socket_dir)
320
321 def _check_gpu_uuid(self, daemon_uuid: str | None) -> None:
322 if daemon_uuid is None:
323 return
332 - props = torch.cuda.get_device_properties(
333 - torch.accelerator.current_device_index()
334 - )
335 - local_uuid = str(props.uuid)
324 + local_uuid = get_current_device_uuid()
325 if daemon_uuid != local_uuid:
326 raise CacheConfigMismatchError(
327 f"Daemon GPU {daemon_uuid} != engine GPU {local_uuid}; "
vllm/model_executor/model_loader/weight_cache/protocol.py
+11 -27
@@ -23,14 +23,19 @@ from dataclasses import dataclass, fields
23 from typing import Any
24
25 import torch
26 +from torch.multiprocessing.reductions import rebuild_cuda_tensor, reduce_tensor
27 +from transformers.utils import SAFE_WEIGHTS_INDEX_NAME
28
29 import vllm.version
30 from vllm.config import ModelConfig
31 from vllm.model_executor.layers.quantization.base_config import QuantizeMethodBase
32 +from vllm.model_executor.model_loader.weight_utils import (
33 + filter_duplicate_safetensors_files,
34 +)
35 from vllm.platforms import current_platform
36 from vllm.utils.hashing import safe_hash
37
33 -SOCKET_NAME_TEMPLATE = "vllm_weight_cache_gpu{gpu_id}.sock"
38 +SOCKET_NAME_TEMPLATE = "vllm_weight_cache_{gpu_uuid}.sock"
39 SOCKET_DIR_TEMPLATE = "vllm_weight_cache_{uid}"
40
41 _LEN_STRUCT = struct.Struct("!Q")
@@ -102,20 +107,9 @@ def check_ipc_quant_support(model: torch.nn.Module) -> None:
107 )
108
109
105 -def get_physical_device_id(device_index: int) -> int | None:
106 - """Map a local CUDA device index to the physical GPU id.
107 -
108 - Returns None if CUDA_VISIBLE_DEVICES contains non-integer entries
109 - (e.g. GPU UUIDs), in which case an explicit socket path is required.
110 - """
111 - visible = os.environ.get("CUDA_VISIBLE_DEVICES")
112 - if not visible:
113 - return device_index
114 - entries = visible.split(",")
115 - try:
116 - return int(entries[device_index])
117 - except (IndexError, ValueError):
118 - return None
110 +def get_current_device_uuid() -> str:
111 + """UUID of the physical GPU backing the current accelerator device."""
112 + return current_platform.get_device_uuid(torch.accelerator.current_device_index())
113
114
115 def get_socket_dir(socket_dir: str | None = None) -> str:
@@ -132,9 +126,9 @@ def get_socket_dir(socket_dir: str | None = None) -> str:
126 )
127
128
135 -def get_socket_path(gpu_id: int, socket_dir: str | None = None) -> str:
129 +def get_socket_path(gpu_uuid: str, socket_dir: str | None = None) -> str:
130 directory = get_socket_dir(socket_dir)
137 - return os.path.join(directory, SOCKET_NAME_TEMPLATE.format(gpu_id=gpu_id))
131 + return os.path.join(directory, SOCKET_NAME_TEMPLATE.format(gpu_uuid=gpu_uuid))
132
133
134 def ensure_private_socket_dir(directory: str, strict_perms: bool = True) -> None:
@@ -245,12 +239,6 @@ def hash_checkpoint(model: str) -> str | None:
239 """
240 if not os.path.isdir(model):
241 return None
248 - from transformers.utils import SAFE_WEIGHTS_INDEX_NAME
249 -
250 - from vllm.model_executor.model_loader.weight_utils import (
251 - filter_duplicate_safetensors_files,
252 - )
253 -
242 files = glob.glob(os.path.join(model, "*.safetensors"))
243 if os.path.isfile(os.path.join(model, SAFE_WEIGHTS_INDEX_NAME)):
244 files = filter_duplicate_safetensors_files(
@@ -337,8 +325,6 @@ class TensorEntry:
325
326 @classmethod
327 def from_tensor(cls, tensor: torch.Tensor, kind: str) -> "TensorEntry":
340 - from torch.multiprocessing.reductions import reduce_tensor
341 -
328 tensor = tensor.detach()
329 if tensor.is_cuda:
330 _, ipc_args = reduce_tensor(tensor)
@@ -349,8 +335,6 @@ class TensorEntry:
335 if self.ipc_args is None:
336 assert self.cpu_tensor is not None
337 return self.cpu_tensor
352 - from torch.multiprocessing.reductions import rebuild_cuda_tensor
353 -
338 args = list(self.ipc_args)
339 # Index 6 of the args from reduce_tensor is the device index. It must
340 # be retargeted to the local index since the daemon and the engine may