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 3, 05:30 UTC
[Feature] Support manually enabling the cumem allocator (#33648)
Signed-off-by: Kebe <mail@kebe7jun.com>
Kebe committed
May 20, 2026 at 21:58 UTC
19cf334207ed81d3ed75a473acd1a95c785d9ed3
6 files changed
+60
-17
docs/features/nixl_connector_usage.md
+4
@@ -375,6 +375,10 @@ The `kv_load_failure_policy` setting controls how the system handles failures wh
375
!!! warning
376
Using `kv_load_failure_policy="recompute"` can lead to performance degradation in production deployments. When KV loads fail, the decode instance will execute prefill work with decode-optimized configurations, which is inefficient and defeats the purpose of disaggregated prefilling. This also increases tail latency for other ongoing decode requests.
377
378
+### For NVIDIA GB-series GPUs
379
+
380
+GB-series GPUs support multi-node NVLink. NIXL supports this capability, but KVCache must be registered as VMM during KVCache registration. To enable this feature, you need to set `--enable-cumem-allocator` or `--enable-sleep-mode` flags, and set `UCX_CUDA_IPC_ENABLE_MNNVL: 'y'` env. Otherwise, NIXL can only use RDMA/TCP for cross-node KVCache transfers.
381
+
382
## Experimental Feature
383
384
### Heterogeneous KV Layout support
tests/v1/kv_connector/unit/test_config.py
+16
-2
@@ -66,7 +66,10 @@ def test_kv_connector(
66
67
68
def _build_config(
69
- *, kv_connector: str | None, enable_sleep_mode: bool = False
69
+ *,
70
+ kv_connector: str | None,
71
+ enable_sleep_mode: bool = False,
72
+ enable_cumem_allocator: bool = False,
73
) -> VllmConfig:
74
"""Build a VllmConfig that exercises _verify_kv_transfer_compat without
75
requiring a real model (avoids HF downloads in CI)."""
@@ -79,7 +82,10 @@ def _build_config(
82
)
83
cfg = VllmConfig.__new__(VllmConfig)
84
cfg.kv_transfer_config = kv_transfer_config
82
- cfg.model_config = SimpleNamespace(enable_sleep_mode=enable_sleep_mode)
85
+ cfg.model_config = SimpleNamespace(
86
+ enable_sleep_mode=enable_sleep_mode,
87
+ enable_cumem_allocator=(enable_cumem_allocator or enable_sleep_mode),
88
+ )
89
cfg._verify_kv_transfer_compat()
90
return cfg
91
@@ -105,6 +111,14 @@ def test_kv_connector_allows_expandable_segments_with_sleep_mode(monkeypatch):
111
_build_config(kv_connector="NixlConnector", enable_sleep_mode=True)
112
113
114
+def test_kv_connector_allows_expandable_segments_with_cumem_allocator(
115
+ monkeypatch,
116
+):
117
+ """Manual CuMem allocation must also bypass expandable_segments."""
118
+ monkeypatch.setenv("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
119
+ _build_config(kv_connector="NixlConnector", enable_cumem_allocator=True)
120
+
121
+
122
def test_kv_connector_allows_other_alloc_conf(monkeypatch):
123
"""Other PYTORCH_CUDA_ALLOC_CONF values must not be rejected."""
124
monkeypatch.setenv(
vllm/config/model.py
+27
-2
@@ -80,6 +80,16 @@ else:
80
81
logger = init_logger(__name__)
82
83
+
84
+def is_cumem_allocator_available() -> bool:
85
+ try:
86
+ from vllm.device_allocator.cumem import cumem_available
87
+ except ImportError:
88
+ return False
89
+
90
+ return cumem_available
91
+
92
+
93
RunnerOption = Literal["auto", RunnerType]
94
ConvertType = Literal["none", "embed", "classify"]
95
ConvertOption = Literal["auto", ConvertType]
@@ -295,6 +305,13 @@ class ModelConfig:
305
enable_sleep_mode: bool = False
306
"""Enable sleep mode for the engine (only cuda and
307
hip platforms are supported)."""
308
+ enable_cumem_allocator: bool = False
309
+ """Enable the custom cumem allocator to leverage advanced GPU memory
310
+ allocation features such as multi-node NVLink support.
311
+
312
+ Sleep mode automatically enables this allocator. Only cuda and hip
313
+ platforms are supported.
314
+ """
315
model_impl: str | ModelImpl = "auto"
316
"""Which implementation of the model to use:
317
@@ -510,8 +527,16 @@ class ModelConfig:
527
stacklevel=2,
528
)
529
513
- if self.enable_sleep_mode and not current_platform.is_sleep_mode_available():
514
- raise ValueError("Sleep mode is not supported on current platform.")
530
+ if self.enable_sleep_mode:
531
+ if not current_platform.is_sleep_mode_available():
532
+ raise ValueError("Sleep mode is not supported on current platform.")
533
+ if not self.enable_cumem_allocator:
534
+ logger.info_once(
535
+ "Enabling cumem allocator because sleep mode requires it."
536
+ )
537
+ self.enable_cumem_allocator = True
538
+ if self.enable_cumem_allocator and not is_cumem_allocator_available():
539
+ raise ValueError("cumem allocator is not supported on current platform.")
540
541
hf_config = get_config(
542
self.hf_config_path or self.model,
vllm/config/vllm.py
+5
-4
@@ -786,7 +786,7 @@ class VllmConfig:
786
# pins memory, so we conservatively reject the combination whenever
787
# any KV connector is configured.
788
#
789
- # Sleep mode is exempt: CuMemAllocator.use_memory_pool toggles
789
+ # CuMem allocator is exempt: CuMemAllocator.use_memory_pool toggles
790
# expandable_segments off around its pool (see #40812), so the KV
791
# cache allocated within that context lands on stable physical pages
792
# even when the env var is set.
@@ -794,17 +794,18 @@ class VllmConfig:
794
"PYTORCH_CUDA_ALLOC_CONF", ""
795
):
796
return
797
- if self.model_config is not None and self.model_config.enable_sleep_mode:
797
+ if self.model_config is not None and (self.model_config.enable_cumem_allocator):
798
return
799
800
raise ValueError(
801
f"KV connector {self.kv_transfer_config.kv_connector} is "
802
"incompatible with PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True "
803
- "unless enable_sleep_mode is also enabled. PyTorch's CUDA VMM "
803
+ "unless enable_cumem_allocator is also enabled. PyTorch's CUDA VMM "
804
"allocator can remap KV cache virtual addresses to different "
805
"physical pages, invalidating any pinned/registered KV memory "
806
"(e.g. IB memory regions registered by NIXL or Mooncake). Either "
807
- "unset expandable_segments:True or enable sleep mode (which "
807
+ "unset expandable_segments:True or enable the cumem allocator "
808
+ "(sleep mode does this automatically and also "
809
"routes KV allocations through CuMemAllocator's pool, where "
810
"expandable_segments is automatically disabled)."
811
)
vllm/engine/arg_utils.py
+5
@@ -655,6 +655,7 @@ class EngineArgs:
655
656
generation_config: str = ModelConfig.generation_config
657
enable_sleep_mode: bool = ModelConfig.enable_sleep_mode
658
+ enable_cumem_allocator: bool = ModelConfig.enable_cumem_allocator
659
override_generation_config: dict[str, Any] = get_field(
660
ModelConfig, "override_generation_config"
661
)
@@ -839,6 +840,9 @@ class EngineArgs:
840
model_group.add_argument(
841
"--enable-sleep-mode", **model_kwargs["enable_sleep_mode"]
842
)
843
+ model_group.add_argument(
844
+ "--enable-cumem-allocator", **model_kwargs["enable_cumem_allocator"]
845
+ )
846
model_group.add_argument("--model-impl", **model_kwargs["model_impl"])
847
model_group.add_argument(
848
"--override-attention-dtype", **model_kwargs["override_attention_dtype"]
@@ -1590,6 +1594,7 @@ class EngineArgs:
1594
generation_config=self.generation_config,
1595
override_generation_config=self.override_generation_config,
1596
enable_sleep_mode=self.enable_sleep_mode,
1597
+ enable_cumem_allocator=self.enable_cumem_allocator,
1598
model_impl=self.model_impl,
1599
override_attention_dtype=self.override_attention_dtype,
1600
logits_processors=self.logits_processors,
vllm/v1/worker/gpu_worker.py
+3
-9
@@ -199,7 +199,7 @@ class Worker(WorkerBase):
199
self.model_runner.post_kv_cache_wake_up()
200
201
def _maybe_get_memory_pool_context(self, tag: str) -> AbstractContextManager:
202
- if not self.vllm_config.model_config.enable_sleep_mode:
202
+ if not self.vllm_config.model_config.enable_cumem_allocator:
203
return nullcontext()
204
205
from vllm.device_allocator.cumem import CuMemAllocator
@@ -207,7 +207,7 @@ class Worker(WorkerBase):
207
allocator = CuMemAllocator.get_instance()
208
if tag == "weights":
209
assert allocator.get_current_usage() == 0, (
210
- "Sleep mode can only be used for one instance per process."
210
+ "CuMem allocator can only be used for one instance per process."
211
)
212
return allocator.use_memory_pool(tag=tag)
213
@@ -550,13 +550,7 @@ class Worker(WorkerBase):
550
# related to kv cache connector (e.g. kv cache sharing layers).
551
ensure_kv_transfer_initialized(self.vllm_config, kv_cache_config)
552
553
- if self.vllm_config.model_config.enable_sleep_mode:
554
- from vllm.device_allocator.cumem import CuMemAllocator
555
-
556
- allocator = CuMemAllocator.get_instance()
557
- with allocator.use_memory_pool(tag="kv_cache"):
558
- self.model_runner.initialize_kv_cache(kv_cache_config)
559
- else:
553
+ with self._maybe_get_memory_pool_context(tag="kv_cache"):
554
self.model_runner.initialize_kv_cache(kv_cache_config)
555
556
if self.model_config.enable_return_routed_experts: