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 15, 18:30 UTC
[Misc] Better RayExecutor and multiprocessing compatibility (#14705)
Signed-off-by: Cody Yu <hao.yu.cody@gmail.com>
Cody Yu committed
Mar 20, 2025 at 19:27 UTC
5df2da5b974d577cb98944c057de435dfd615cac
4 files changed
+67
-21
vllm/engine/arg_utils.py
+14
-1
@@ -26,7 +26,7 @@ from vllm.plugins import load_general_plugins
26
from vllm.test_utils import MODEL_WEIGHTS_S3_BUCKET, MODELS_ON_S3
27
from vllm.transformers_utils.utils import check_gguf_file
28
from vllm.usage.usage_lib import UsageContext
29
-from vllm.utils import FlexibleArgumentParser, StoreBoolean
29
+from vllm.utils import FlexibleArgumentParser, StoreBoolean, is_in_ray_actor
30
31
if TYPE_CHECKING:
32
from vllm.transformers_utils.tokenizer_group import BaseTokenizerGroup
@@ -1245,6 +1245,18 @@ class EngineArgs:
1245
cpu_offload_gb=self.cpu_offload_gb,
1246
calculate_kv_scales=self.calculate_kv_scales,
1247
)
1248
+
1249
+ # Get the current placement group if Ray is initialized and
1250
+ # we are in a Ray actor. If so, then the placement group will be
1251
+ # passed to spawned processes.
1252
+ placement_group = None
1253
+ if is_in_ray_actor():
1254
+ import ray
1255
+
1256
+ # This call initializes Ray automatically if it is not initialized,
1257
+ # but we should not do this here.
1258
+ placement_group = ray.util.get_current_placement_group()
1259
+
1260
parallel_config = ParallelConfig(
1261
pipeline_parallel_size=self.pipeline_parallel_size,
1262
tensor_parallel_size=self.tensor_parallel_size,
@@ -1257,6 +1269,7 @@ class EngineArgs:
1269
self.tokenizer_pool_extra_config,
1270
),
1271
ray_workers_use_nsight=self.ray_workers_use_nsight,
1272
+ placement_group=placement_group,
1273
distributed_executor_backend=self.distributed_executor_backend,
1274
worker_cls=self.worker_cls,
1275
worker_extension_cls=self.worker_extension_cls,
vllm/executor/multiproc_worker_utils.py
+2
-2
@@ -16,7 +16,7 @@ import torch
16
17
from vllm.config import VllmConfig
18
from vllm.logger import init_logger
19
-from vllm.utils import _check_multiproc_method, get_mp_context, run_method
19
+from vllm.utils import _maybe_force_spawn, get_mp_context, run_method
20
21
logger = init_logger(__name__)
22
@@ -291,7 +291,7 @@ def set_multiprocessing_worker_envs(parallel_config):
291
in a multiprocessing environment. This should be called by the parent
292
process before worker processes are created"""
293
294
- _check_multiproc_method()
294
+ _maybe_force_spawn()
295
296
# Configure thread parallelism if OMP_NUM_THREADS isn't set
297
#
vllm/executor/ray_utils.py
+13
-8
@@ -284,8 +284,9 @@ def initialize_ray_cluster(
284
assert_ray_available()
285
from vllm.platforms import current_platform
286
287
- # Connect to a ray cluster.
288
- if current_platform.is_rocm() or current_platform.is_xpu():
287
+ if ray.is_initialized():
288
+ logger.info("Ray is already initialized. Skipping Ray initialization.")
289
+ elif current_platform.is_rocm() or current_platform.is_xpu():
290
# Try to connect existing ray instance and create a new one if not found
291
try:
292
ray.init("auto", ignore_reinit_error=True)
@@ -299,19 +300,21 @@ def initialize_ray_cluster(
300
else:
301
ray.init(address=ray_address, ignore_reinit_error=True)
302
302
- if parallel_config.placement_group:
303
- # Placement group is already set.
304
- return
305
-
303
device_str = current_platform.ray_device_key
304
if not device_str:
305
raise ValueError(
306
f"current platform {current_platform.device_name} does not "
307
"support ray.")
308
312
- # Create placement group for worker processes
313
- current_placement_group = ray.util.get_current_placement_group()
309
+ # Create or get the placement group for worker processes
310
+ if parallel_config.placement_group:
311
+ current_placement_group = parallel_config.placement_group
312
+ else:
313
+ current_placement_group = ray.util.get_current_placement_group()
314
+
315
if current_placement_group:
316
+ logger.info("Using the existing placement group")
317
+
318
# We are in a placement group
319
bundles = current_placement_group.bundle_specs
320
# Verify that we can use the placement group.
@@ -331,6 +334,8 @@ def initialize_ray_cluster(
334
f"Required number of devices: {parallel_config.world_size}. "
335
f"Total number of devices: {device_bundles}.")
336
else:
337
+ logger.info("No current placement group found. "
338
+ "Creating a new placement group.")
339
num_devices_in_cluster = ray.cluster_resources().get(device_str, 0)
340
# Log a warning message and delay resource allocation failure response.
341
# Avoid immediate rejection to allow user-initiated placement group
vllm/utils.py
+38
-10
@@ -2147,20 +2147,48 @@ def zmq_socket_ctx(path: str, socket_type: Any) -> Iterator[zmq.Socket]:
2147
ctx.destroy(linger=0)
2148
2149
2150
-def _check_multiproc_method():
2151
- if (cuda_is_initialized()
2152
- and os.environ.get("VLLM_WORKER_MULTIPROC_METHOD") != "spawn"):
2153
- logger.warning("CUDA was previously initialized. We must use "
2154
- "the `spawn` multiprocessing start method. Setting "
2155
- "VLLM_WORKER_MULTIPROC_METHOD to 'spawn'. "
2156
- "See https://docs.vllm.ai/en/latest/getting_started/"
2157
- "troubleshooting.html#python-multiprocessing "
2158
- "for more information.")
2150
+def is_in_ray_actor():
2151
+ """Check if we are in a Ray actor."""
2152
+
2153
+ try:
2154
+ import ray
2155
+ return (ray.is_initialized()
2156
+ and ray.get_runtime_context().get_actor_id() is not None)
2157
+ except ImportError:
2158
+ return False
2159
+
2160
+
2161
+def _maybe_force_spawn():
2162
+ """Check if we need to force the use of the `spawn` multiprocessing start
2163
+ method.
2164
+ """
2165
+ if os.environ.get("VLLM_WORKER_MULTIPROC_METHOD") == "spawn":
2166
+ return
2167
+
2168
+ reason = None
2169
+ if cuda_is_initialized():
2170
+ reason = "CUDA is initialized"
2171
+ elif is_in_ray_actor():
2172
+ reason = "In a Ray actor and can only be spawned"
2173
+
2174
+ if reason is not None:
2175
+ logger.warning(
2176
+ "We must use the `spawn` multiprocessing start method. "
2177
+ "Overriding VLLM_WORKER_MULTIPROC_METHOD to 'spawn'. "
2178
+ "See https://docs.vllm.ai/en/latest/getting_started/"
2179
+ "troubleshooting.html#python-multiprocessing "
2180
+ "for more information. Reason: %s", reason)
2181
os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"
2182
2183
2184
def get_mp_context():
2163
- _check_multiproc_method()
2185
+ """Get a multiprocessing context with a particular method (spawn or fork).
2186
+ By default we follow the value of the VLLM_WORKER_MULTIPROC_METHOD to
2187
+ determine the multiprocessing method (default is fork). However, under
2188
+ certain conditions, we may enforce spawn and override the value of
2189
+ VLLM_WORKER_MULTIPROC_METHOD.
2190
+ """
2191
+ _maybe_force_spawn()
2192
mp_method = envs.VLLM_WORKER_MULTIPROC_METHOD
2193
return multiprocessing.get_context(mp_method)
2194