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 10, 11:30 UTC
[Misc] Fix `Current vLLM config is not set.` warnings, assert to avoid issues in the future (#31747)
Signed-off-by: Lucas Wilkinson <lwilkins@redhat.com> Signed-off-by: Lucas Wilkinson <LucasWilkinson@users.noreply.github.com> Co-authored-by: Luka Govedič <ProExpertProg@users.noreply.github.com>
Lucas Wilkinson committed
Jan 8, 2026 at 18:20 UTC
6cdf015c3cd8ee600dadf17ecd72fc7f44099d03
48 files changed
+380
-240
tests/compile/distributed/test_async_tp.py
+29
-24
@@ -15,6 +15,7 @@ from vllm.config import (
15
ModelConfig,
16
PassConfig,
17
VllmConfig,
18
+ set_current_vllm_config,
19
)
20
from vllm.distributed import (
21
tensor_model_parallel_all_gather,
@@ -340,38 +341,42 @@ def async_tp_pass_on_test_model(
341
)
342
343
async_tp_pass = AsyncTPPass(vllm_config)
343
- backend = TestBackend(async_tp_pass)
344
345
- assert (
346
- async_tp_pass.compilation_config.splitting_ops
347
- == vllm_config.compilation_config.splitting_ops
348
- )
349
- assert (
350
- async_tp_pass.compilation_config.use_inductor_graph_partition
351
- == vllm_config.compilation_config.use_inductor_graph_partition
352
- )
345
+ # Set the global vllm_config for TestBackend which calls
346
+ # get_current_vllm_config()
347
+ with set_current_vllm_config(vllm_config):
348
+ backend = TestBackend(async_tp_pass)
349
354
- model = test_model_cls(hidden_size, dtype) # Pass dtype to model constructor
350
+ assert (
351
+ async_tp_pass.compilation_config.splitting_ops
352
+ == vllm_config.compilation_config.splitting_ops
353
+ )
354
+ assert (
355
+ async_tp_pass.compilation_config.use_inductor_graph_partition
356
+ == vllm_config.compilation_config.use_inductor_graph_partition
357
+ )
358
356
- hidden_states = torch.randn(
357
- (batch_size * seq_len, hidden_size), dtype=dtype, requires_grad=False
358
- )
359
+ model = test_model_cls(hidden_size, dtype) # Pass dtype to model constructor
360
+
361
+ hidden_states = torch.randn(
362
+ (batch_size * seq_len, hidden_size), dtype=dtype, requires_grad=False
363
+ )
364
360
- if dynamic:
361
- torch._dynamo.mark_dynamic(hidden_states, 0)
365
+ if dynamic:
366
+ torch._dynamo.mark_dynamic(hidden_states, 0)
367
363
- compiled_model = torch.compile(model, backend=backend)
364
- compiled_model(hidden_states)
368
+ compiled_model = torch.compile(model, backend=backend)
369
+ compiled_model(hidden_states)
370
366
- assert async_tp_pass.matched_count == 1
371
+ assert async_tp_pass.matched_count == 1
372
368
- # In pre-nodes, all gather or reduce scatter should exist,
369
- # fused_matmul_reduce_scatter or fused_all_gather_matmul should not
370
- backend.check_before_ops(model.ops_in_model_before(), fully_replaced=False)
373
+ # In pre-nodes, all gather or reduce scatter should exist,
374
+ # fused_matmul_reduce_scatter or fused_all_gather_matmul should not
375
+ backend.check_before_ops(model.ops_in_model_before(), fully_replaced=False)
376
372
- # In post-nodes, fused_matmul_reduce_scatter or \
373
- # fused_all_gather_matmul should exist
374
- backend.check_after_ops(model.ops_in_model_after())
377
+ # In post-nodes, fused_matmul_reduce_scatter or \
378
+ # fused_all_gather_matmul should exist
379
+ backend.check_after_ops(model.ops_in_model_after())
380
381
382
@create_new_process_for_each_test()
tests/compile/test_config.py
+1
-1
@@ -430,7 +430,7 @@ def test_cudagraph_sizes_post_init(
430
)
431
432
433
-def test_cached_compilation_config():
433
+def test_cached_compilation_config(default_vllm_config):
434
import torch
435
from torch._inductor.utils import run_and_get_code
436
tests/conftest.py
+11
@@ -189,6 +189,17 @@ def dist_init():
189
cleanup_dist_env_and_memory()
190
191
192
+@pytest.fixture
193
+def default_vllm_config():
194
+ """Set a default VllmConfig for tests that directly test CustomOps or pathways
195
+ that use get_current_vllm_config() outside of a full engine context.
196
+ """
197
+ from vllm.config import VllmConfig, set_current_vllm_config
198
+
199
+ with set_current_vllm_config(VllmConfig()):
200
+ yield
201
+
202
+
203
@pytest.fixture()
204
def should_do_global_cleanup_after_test(request) -> bool:
205
"""Allow subdirectories to skip global cleanup by overriding this fixture.
tests/kernels/attention/test_flashinfer_trtllm_attention.py
+1
-1
@@ -458,7 +458,7 @@ def test_flashinfer_trtllm_prefill_with_baseline(
458
)
459
460
461
-def test_trtllm_attention_rejects_num_kv_heads_1() -> None:
461
+def test_trtllm_attention_rejects_num_kv_heads_1(default_vllm_config) -> None:
462
"""Test that TRTLLM attention correctly rejects num_kv_heads=1.
463
464
When num_kv_heads=1 (MQA), the KV cache strides become degenerate
tests/kernels/attention/test_mha_attn.py
+3
-1
@@ -36,7 +36,7 @@ if current_platform.is_rocm():
36
37
38
@pytest.mark.parametrize("device", devices)
39
-def test_mha_attn_platform(device: str):
39
+def test_mha_attn_platform(default_vllm_config, device: str):
40
"""
41
Test the attention selector between different platform and device.
42
"""
@@ -116,6 +116,7 @@ CUDA_DEVICES = ["cuda"]
116
@pytest.mark.parametrize("dtype", DTYPES)
117
@pytest.mark.parametrize("device", CUDA_DEVICES)
118
def test_mha_attn_forward(
119
+ default_vllm_config,
120
batch_size: int,
121
seq_len: int,
122
num_heads: int,
@@ -162,6 +163,7 @@ def test_mha_attn_forward(
163
@pytest.mark.parametrize("dtype", DTYPES)
164
@pytest.mark.parametrize("device", CUDA_DEVICES)
165
def test_mha_attn_varlen_forward(
166
+ default_vllm_config,
167
var_seq_len: list[int],
168
num_heads: int,
169
num_kv_heads: int,
tests/kernels/core/test_activation.py
+2
@@ -45,6 +45,7 @@ CUDA_DEVICES = [f"cuda:{i}" for i in range(1 if torch.cuda.device_count() == 1 e
45
@pytest.mark.parametrize("device", CUDA_DEVICES)
46
@torch.inference_mode()
47
def test_act_and_mul(
48
+ default_vllm_config,
49
activation: str,
50
num_tokens: int,
51
d: int,
@@ -122,6 +123,7 @@ def test_act_and_mul(
123
@pytest.mark.parametrize("device", CUDA_DEVICES)
124
@torch.inference_mode()
125
def test_activation(
126
+ default_vllm_config,
127
activation: type[torch.nn.Module],
128
num_tokens: int,
129
d: int,
tests/kernels/core/test_fused_qk_norm_rope.py
+1
@@ -57,6 +57,7 @@ def _apply_qk_norm_rope(
57
@pytest.mark.parametrize("rotary_ratio", [1.0, 0.5, 0.25])
58
@torch.inference_mode()
59
def test_fused_qk_norm_rope_matches_reference(
60
+ default_vllm_config,
61
device: str,
62
dtype: torch.dtype,
63
is_neox: bool,
tests/kernels/core/test_fused_quant_layernorm.py
+1
@@ -147,6 +147,7 @@ def ops_impl(
147
@pytest.mark.parametrize("device", CUDA_DEVICES)
148
@torch.inference_mode()
149
def test_rms_norm(
150
+ default_vllm_config,
151
num_tokens: int,
152
hidden_size: int,
153
add_residual: bool,
tests/kernels/core/test_layernorm.py
+1
@@ -26,6 +26,7 @@ CUDA_DEVICES = [f"cuda:{i}" for i in range(1 if torch.cuda.device_count() == 1 e
26
@pytest.mark.parametrize("strided_input", [False, True])
27
@torch.inference_mode()
28
def test_rms_norm(
29
+ default_vllm_config,
30
num_tokens: int,
31
hidden_size: int,
32
add_residual: bool,
tests/kernels/core/test_mrope.py
+2
@@ -90,6 +90,7 @@ num_tokens_list = [11, 8192]
90
@pytest.mark.parametrize("dtype", [torch.bfloat16])
91
@pytest.mark.parametrize("num_tokens", num_tokens_list)
92
def test_mrope(
93
+ default_vllm_config,
94
model_name: str,
95
model_info: MRoPETestInfo,
96
tp_size: int,
@@ -159,6 +160,7 @@ def test_mrope(
160
@pytest.mark.parametrize("dtype", [torch.bfloat16])
161
@pytest.mark.parametrize("num_tokens", num_tokens_list)
162
def test_mrope_torch_compile_tracing(
163
+ default_vllm_config,
164
model_name: str,
165
model_info: MRoPETestInfo,
166
tp_size: int,
tests/kernels/core/test_pos_encoding.py
+2
-1
@@ -62,6 +62,7 @@ TENSORS_SHAPES_FN = [
62
@pytest.mark.parametrize("use_key", USE_KEY)
63
@torch.inference_mode()
64
def test_rotary_embedding(
65
+ default_vllm_config,
66
is_neox_style: bool,
67
tensor_shape_fn: Callable[[int, int, int, int], tuple[int, ...]],
68
batch_size: int,
@@ -123,7 +124,7 @@ def test_rotary_embedding(
124
125
126
@torch.inference_mode()
126
-def test_rope_module_cache():
127
+def test_rope_module_cache(default_vllm_config):
128
MAX_POSITIONS = [123, 1234]
129
ROPE_THETAS = [10000, 1000000]
130
ROPE_PARAMETERS = (
tests/kernels/core/test_rotary_embedding.py
+1
@@ -36,6 +36,7 @@ def rotary_embedding_opcheck(
36
@pytest.mark.parametrize("use_key", [True, False])
37
@pytest.mark.parametrize("head_stride_is_contiguous", [True, False])
38
def test_rotary_embedding_opcheck(
39
+ default_vllm_config,
40
dist_init,
41
device,
42
max_position,
tests/kernels/moe/test_cpu_fused_moe.py
+2
-6
@@ -6,7 +6,7 @@ import torch
6
7
from tests.kernels.allclose_default import get_default_atol, get_default_rtol
8
from vllm._custom_ops import cpu_fused_moe, cpu_prepack_moe_weight
9
-from vllm.model_executor.layers.activation import SiluAndMul, SwigluOAIAndMul
9
+from vllm.model_executor.layers.fused_moe.cpu_fused_moe import _CPU_MOE_ACT
10
from vllm.platforms import current_platform
11
from vllm.utils.torch_utils import set_random_seed
12
@@ -24,11 +24,6 @@ USE_BIAS = [True, False]
24
ISA = ["amx", "vec"] if torch._C._cpu._is_amx_tile_supported() else ["vec"]
25
DTYPE = [torch.bfloat16]
26
27
-_CPU_MOE_ACT = {
28
- "silu": SiluAndMul(),
29
- "swigluoai": SwigluOAIAndMul(),
30
-}
31
-
27
28
def ref_fused_moe(
29
input: torch.Tensor,
@@ -106,6 +101,7 @@ def ref_fused_moe(
101
@pytest.mark.parametrize("act", ACT)
102
@pytest.mark.parametrize("isa", ISA)
103
def test_cpu_fused_moe(
104
+ default_vllm_config,
105
batch_size: int,
106
expert_num: int,
107
hidden_size: int,
tests/kernels/moe/test_moe.py
+6
-1
@@ -468,7 +468,12 @@ def test_fused_moe_wn16(
468
)
469
@torch.inference_mode()
470
def test_mixtral_moe(
471
- dist_init, dtype: torch.dtype, padding: bool, use_rocm_aiter: bool, monkeypatch
471
+ default_vllm_config,
472
+ dist_init,
473
+ dtype: torch.dtype,
474
+ padding: bool,
475
+ use_rocm_aiter: bool,
476
+ monkeypatch,
477
):
478
"""Make sure our Mixtral MoE implementation agrees with the one from
479
huggingface."""
tests/kernels/quantization/test_fp8_quant_group.py
+10
-3
@@ -23,7 +23,12 @@ from vllm.utils.torch_utils import set_random_seed
23
@pytest.mark.parametrize("use_ue8m0", [True, False])
24
@torch.inference_mode()
25
def test_quantfp8_group_functionality(
26
- batch_size: int, hidden_dim: int, group_size: int, seed: int, use_ue8m0: bool
26
+ default_vllm_config,
27
+ batch_size: int,
28
+ hidden_dim: int,
29
+ group_size: int,
30
+ seed: int,
31
+ use_ue8m0: bool,
32
) -> None:
33
"""Test QuantFP8 group quantization with various configurations.
34
@@ -82,7 +87,9 @@ def test_quantfp8_group_functionality(
87
@pytest.mark.parametrize("seed", [42])
88
@pytest.mark.parametrize("use_ue8m0", [True, False])
89
@torch.inference_mode()
85
-def test_quantfp8_group_multidimensional(seed: int, use_ue8m0: bool) -> None:
90
+def test_quantfp8_group_multidimensional(
91
+ default_vllm_config, seed: int, use_ue8m0: bool
92
+) -> None:
93
set_random_seed(seed)
94
95
group_size = 64
@@ -135,7 +142,7 @@ def test_quantfp8_group_multidimensional(seed: int, use_ue8m0: bool) -> None:
142
143
@pytest.mark.parametrize("seed", [42])
144
@torch.inference_mode()
138
-def test_quantfp8_group_edge_cases(seed: int) -> None:
145
+def test_quantfp8_group_edge_cases(default_vllm_config, seed: int) -> None:
146
set_random_seed(seed)
147
148
batch_size = 16
tests/kernels/quantization/test_int8_kernel.py
+1
-1
@@ -102,7 +102,7 @@ SEEDS = [0]
102
itertools.product(M, N, K, E, TOP_KS, DTYPES, SEEDS),
103
)
104
@torch.inference_mode()
105
-def test_w8a8_fp8_fused_moe(M, N, K, E, topk, dtype, seed):
105
+def test_w8a8_fp8_fused_moe(default_vllm_config, M, N, K, E, topk, dtype, seed):
106
torch.manual_seed(seed)
107
# Initialize int8 quantization parameters
108
factor_for_scale = 1e-2
tests/kernels/quantization/test_silu_mul_nvfp4_quant.py
+1
@@ -31,6 +31,7 @@ BLOCK_SIZE = 16
31
@pytest.mark.parametrize("shape", SHAPES)
32
@torch.inference_mode()
33
def test_silu_mul_nvfp4_quant(
34
+ default_vllm_config,
35
dtype: torch.dtype,
36
shape: tuple[int, int],
37
) -> None:
tests/kernels/test_fused_quant_activation.py
+1
@@ -39,6 +39,7 @@ def ops_impl(x: torch.Tensor, scale: torch.Tensor) -> torch.Tensor:
39
@pytest.mark.parametrize("device", CUDA_DEVICES)
40
@torch.inference_mode()
41
def test_silu_and_mul(
42
+ default_vllm_config,
43
num_tokens: int,
44
hidden_size: int,
45
dtype: torch.dtype,
tests/lora/conftest.py
+2
-2
@@ -82,7 +82,7 @@ class DummyLoRAModel(nn.Sequential, SupportsLoRA):
82
83
84
@pytest.fixture
85
-def dummy_model() -> nn.Module:
85
+def dummy_model(default_vllm_config) -> nn.Module:
86
model = DummyLoRAModel(
87
OrderedDict(
88
[
@@ -115,7 +115,7 @@ def dummy_model() -> nn.Module:
115
116
117
@pytest.fixture
118
-def dummy_model_gate_up() -> nn.Module:
118
+def dummy_model_gate_up(default_vllm_config) -> nn.Module:
119
model = DummyLoRAModel(
120
OrderedDict(
121
[
tests/lora/test_layers.py
+8
-5
@@ -252,7 +252,9 @@ def check_punica_wrapper(punica_wrapper) -> bool:
252
@pytest.mark.parametrize("device", DEVICES)
253
@pytest.mark.parametrize("vocab_size", [512, 32000, 64000, 128000])
254
@pytest.mark.parametrize("stage", STAGES)
255
-def test_embeddings(dist_init, num_loras, device, vocab_size, stage) -> None:
255
+def test_embeddings(
256
+ default_vllm_config, dist_init, num_loras, device, vocab_size, stage
257
+) -> None:
258
# For multi-GPU testing of Triton kernel, we must explicitly set the CUDA
259
# device, see: https://github.com/triton-lang/triton/issues/2925
260
# Same below.
@@ -353,7 +355,7 @@ def test_embeddings(dist_init, num_loras, device, vocab_size, stage) -> None:
355
@pytest.mark.parametrize("vocab_size", [512, 32000, 64000, 256512])
356
@pytest.mark.parametrize("stage", STAGES)
357
def test_lm_head_logits_processor(
356
- dist_init, num_loras, device, vocab_size, stage
358
+ default_vllm_config, dist_init, num_loras, device, vocab_size, stage
359
) -> None:
360
if current_platform.is_cuda_alike():
361
torch.cuda.set_device(device)
@@ -470,6 +472,7 @@ def test_lm_head_logits_processor(
472
@pytest.mark.parametrize("device", DEVICES)
473
@pytest.mark.parametrize("stage", STAGES)
474
def test_linear_replicated(
475
+ default_vllm_config,
476
dist_init,
477
num_loras,
478
device,
@@ -580,7 +583,7 @@ def test_linear_replicated(
583
@pytest.mark.parametrize("device", DEVICES)
584
@pytest.mark.parametrize("stage", STAGES)
585
def test_linear_parallel(
583
- dist_init, num_loras, orientation, fully_shard, device, stage
586
+ default_vllm_config, dist_init, num_loras, orientation, fully_shard, device, stage
587
) -> None:
588
if current_platform.is_cuda_alike():
589
torch.cuda.set_device(device)
@@ -705,7 +708,7 @@ def test_linear_parallel(
708
@pytest.mark.parametrize("device", DEVICES)
709
@pytest.mark.parametrize("stage", STAGES)
710
def test_column_parallel_packed(
708
- dist_init, num_loras, repeats, fully_shard, device, stage
711
+ default_vllm_config, dist_init, num_loras, repeats, fully_shard, device, stage
712
) -> None:
713
if current_platform.is_cuda_alike():
714
torch.cuda.set_device(device)
@@ -851,7 +854,7 @@ def test_column_parallel_packed(
854
@pytest.mark.parametrize(
855
"seed", list(range(VOCAB_PARALLEL_EMBEDDING_TEST_NUM_RANDOM_SEEDS))
856
)
854
-def test_vocab_parallel_embedding_indices(tp_size, seed):
857
+def test_vocab_parallel_embedding_indices(tp_size, seed, default_vllm_config):
858
random.seed(seed)
859
vocab_size = random.randint(4000, 64000)
860
added_vocab_size = random.randint(0, 1024)
tests/lora/test_lora_manager.py
+13
-7
@@ -111,7 +111,7 @@ def create_packed_lora(
111
return LoRAModel(lora_id, 8, loras)
112
113
114
-def test_replace_submodules(dist_init, dummy_model):
114
+def test_replace_submodules(default_vllm_config, dist_init, dummy_model):
115
model = dummy_model
116
manager = LoRAModelManager(
117
model,
@@ -133,7 +133,7 @@ def test_replace_submodules(dist_init, dummy_model):
133
134
135
@pytest.mark.parametrize("device", DEVICES)
136
-def test_lora_model_manager(dist_init, dummy_model, device):
136
+def test_lora_model_manager(default_vllm_config, dist_init, dummy_model, device):
137
model = dummy_model
138
model_lora1 = create_lora(
139
1, model, ["layer1.dense1", "dense2", "lm_head"], device=device
@@ -199,7 +199,9 @@ def test_lora_model_manager(dist_init, dummy_model, device):
199
200
201
@pytest.mark.parametrize("device", DEVICES)
202
-def test_lora_lru_cache_model_manager(dist_init, dummy_model, device):
202
+def test_lora_lru_cache_model_manager(
203
+ default_vllm_config, dist_init, dummy_model, device
204
+):
205
model = dummy_model
206
model_lora1 = create_lora(
207
1, model, ["layer1.dense1", "dense2", "lm_head"], device=device
@@ -289,7 +291,7 @@ def test_lora_lru_cache_model_manager(dist_init, dummy_model, device):
291
292
293
@pytest.mark.parametrize("device", DEVICES)
292
-def test_lru_lora_model_manager(dist_init, dummy_model, device):
294
+def test_lru_lora_model_manager(default_vllm_config, dist_init, dummy_model, device):
295
# This tests just the LRU cache functionality, everything else is
296
# tested in test_lora_model_manager
297
model = dummy_model
@@ -415,7 +417,9 @@ def test_lru_lora_model_manager(dist_init, dummy_model, device):
417
418
419
@pytest.mark.parametrize("device", DEVICES)
418
-def test_lru_cache_worker_adapter_manager(dist_init, dummy_model, device, tmp_path):
420
+def test_lru_cache_worker_adapter_manager(
421
+ default_vllm_config, dist_init, dummy_model, device, tmp_path
422
+):
423
lora_config = LoRAConfig(
424
max_lora_rank=8, max_cpu_loras=4, max_loras=4, lora_dtype=DEFAULT_DTYPE
425
)
@@ -529,7 +533,9 @@ def test_lru_cache_worker_adapter_manager(dist_init, dummy_model, device, tmp_pa
533
534
535
@pytest.mark.parametrize("device", DEVICES)
532
-def test_worker_adapter_manager(dist_init, dummy_model_gate_up, device, tmp_path):
536
+def test_worker_adapter_manager(
537
+ default_vllm_config, dist_init, dummy_model_gate_up, device, tmp_path
538
+):
539
# Should remove every LoRA not specified in the request.
540
lora_config = LoRAConfig(
541
max_lora_rank=8, max_cpu_loras=4, max_loras=4, lora_dtype=DEFAULT_DTYPE
@@ -636,7 +642,7 @@ def test_worker_adapter_manager(dist_init, dummy_model_gate_up, device, tmp_path
642
643
644
@pytest.mark.parametrize("device", DEVICES)
639
-def test_packed_loras(dist_init, dummy_model_gate_up, device):
645
+def test_packed_loras(default_vllm_config, dist_init, dummy_model_gate_up, device):
646
model = dummy_model_gate_up
647
model_lora = create_packed_lora(
648
1,
tests/model_executor/test_eagle_quantization.py
+1
-1
@@ -55,7 +55,7 @@ def test_get_draft_quant_config_without_draft_model():
55
56
@torch.inference_mode()
57
@pytest.mark.parametrize("device", DEVICES)
58
-def test_fc_layer_quant_config_usage(dist_init, device) -> None:
58
+def test_fc_layer_quant_config_usage(default_vllm_config, dist_init, device) -> None:
59
import torch
60
61
from vllm.model_executor.layers.linear import ReplicatedLinear
tests/models/multimodal/pooling/test_intern_vit.py
+3
-1
@@ -73,7 +73,9 @@ def run_intern_vit_test(
73
],
74
)
75
@pytest.mark.parametrize("dtype", ["half"])
76
-def test_models(dist_init, image_assets, model_id, dtype: str) -> None:
76
+def test_models(
77
+ default_vllm_config, dist_init, image_assets, model_id, dtype: str
78
+) -> None:
79
run_intern_vit_test(
80
image_assets,
81
model_id,
tests/models/multimodal/pooling/test_radio.py
+3
-1
@@ -92,7 +92,9 @@ def run_radio_test(
92
],
93
)
94
@pytest.mark.parametrize("dtype", ["half", "bfloat16"])
95
-def test_radio(dist_init, image_assets, model_id, dtype: str) -> None:
95
+def test_radio(
96
+ default_vllm_config, dist_init, image_assets, model_id, dtype: str
97
+) -> None:
98
run_radio_test(
99
image_assets,
100
model_id,
tests/models/multimodal/processing/test_tensor_schema.py
+9
-9
@@ -145,18 +145,18 @@ def initialize_dummy_model(
145
model_config: ModelConfig,
146
):
147
temp_file = tempfile.mkstemp()[1]
148
- init_distributed_environment(
149
- world_size=1,
150
- rank=0,
151
- distributed_init_method=f"file://{temp_file}",
152
- local_rank=0,
153
- backend="nccl",
154
- )
155
- initialize_model_parallel(tensor_model_parallel_size=1)
156
-
148
current_device = torch.get_default_device()
149
vllm_config = VllmConfig(model_config=model_config)
150
with set_current_vllm_config(vllm_config=vllm_config):
151
+ init_distributed_environment(
152
+ world_size=1,
153
+ rank=0,
154
+ distributed_init_method=f"file://{temp_file}",
155
+ local_rank=0,
156
+ backend="nccl",
157
+ )
158
+ initialize_model_parallel(tensor_model_parallel_size=1)
159
+
160
with set_default_torch_dtype(model_config.dtype):
161
torch.set_default_device(current_platform.device_type)
162
model = model_cls(vllm_config=vllm_config)
tests/plugins_tests/test_platform_plugins.py
+1
-1
@@ -31,7 +31,7 @@ def test_platform_plugins():
31
)
32
33
34
-def test_oot_custom_op(monkeypatch: pytest.MonkeyPatch):
34
+def test_oot_custom_op(default_vllm_config, monkeypatch: pytest.MonkeyPatch):
35
# simulate workload by running an example
36
load_general_plugins()
37
from vllm.model_executor.layers.rotary_embedding import RotaryEmbedding
tests/quantization/test_fp8.py
+1
@@ -277,6 +277,7 @@ def test_scaled_fp8_quant(dtype) -> None:
277
# this is the case for marlin as well as per-tensor Fp8MoEMethod
278
@pytest.mark.parametrize("use_marlin", [False]) # skip True
279
def test_fp8_reloading(
280
+ default_vllm_config,
281
method_cls,
282
is_checkpoint_fp8_serialized,
283
weight_block_size,
tests/utils.py
+27
-6
@@ -721,13 +721,34 @@ def init_test_distributed_environment(
721
distributed_init_port: str,
722
local_rank: int = -1,
723
) -> None:
724
- distributed_init_method = f"tcp://localhost:{distributed_init_port}"
725
- init_distributed_environment(
726
- world_size=pp_size * tp_size,
727
- rank=rank,
728
- distributed_init_method=distributed_init_method,
729
- local_rank=local_rank,
724
+ # Note: This function is often called from Ray worker processes, so we
725
+ # can't rely on pytest fixtures to set the config. We check if the config
726
+ # is already set and only create a default one if needed.
727
+ from vllm.config import (
728
+ VllmConfig,
729
+ get_current_vllm_config_or_none,
730
+ set_current_vllm_config,
731
)
732
+
733
+ distributed_init_method = f"tcp://localhost:{distributed_init_port}"
734
+
735
+ if get_current_vllm_config_or_none() is not None:
736
+ # Config already set, use it directly
737
+ init_distributed_environment(
738
+ world_size=pp_size * tp_size,
739
+ rank=rank,
740
+ distributed_init_method=distributed_init_method,
741
+ local_rank=local_rank,
742
+ )
743
+ else:
744
+ # No config set, create a default one for the test
745
+ with set_current_vllm_config(VllmConfig()):
746
+ init_distributed_environment(
747
+ world_size=pp_size * tp_size,
748
+ rank=rank,
749
+ distributed_init_method=distributed_init_method,
750
+ local_rank=local_rank,
751
+ )
752
ensure_model_parallel_initialized(tp_size, pp_size)
753
754
tests/v1/attention/test_attention_backends.py
+1
-1
@@ -556,7 +556,7 @@ def _test_backend_correctness(
556
@pytest.mark.parametrize("model", ["meta-llama/Meta-Llama-3-8B"])
557
@pytest.mark.parametrize("tensor_parallel_size", [1, 2, 4])
558
def test_causal_backend_correctness(
559
- batch_spec_name: str, model: str, tensor_parallel_size: int
559
+ default_vllm_config, batch_spec_name: str, model: str, tensor_parallel_size: int
560
):
561
"""Test backend's correctness with causal attention."""
562
tests/v1/attention/test_attention_backends_selection.py
+6
-1
@@ -79,7 +79,12 @@ from vllm.v1.attention.backends.short_conv_attn import ShortConvAttentionBackend
79
],
80
)
81
def test_mamba_layers_get_attn_backend(
82
- dist_init, layer_class, init_kwargs, expected_backend, expected_mamba_type
82
+ default_vllm_config,
83
+ dist_init,
84
+ layer_class,
85
+ init_kwargs,
86
+ expected_backend,
87
+ expected_mamba_type,
88
):
89
"""Test that Mamba-like layers return the correct attention backend."""
90
layer = layer_class(**init_kwargs)
tests/v1/attention/test_mla_backends.py
+5
-1
@@ -394,7 +394,11 @@ def run_attention_backend(
394
@pytest.mark.parametrize("model", ["deepseek-ai/DeepSeek-R1"])
395
@pytest.mark.parametrize("tensor_parallel_size", [1, 4, 8, 16])
396
def test_backend_correctness(
397
- dist_init, batch_spec_name: str, model: str, tensor_parallel_size: int
397
+ default_vllm_config,
398
+ dist_init,
399
+ batch_spec_name: str,
400
+ model: str,
401
+ tensor_parallel_size: int,
402
):
403
"""
404
Test that all backends produce similar outputs to a reference implementation
tests/v1/attention/test_sparse_mla_backends.py
+6
-1
@@ -124,7 +124,12 @@ def _quantize_dequantize_fp8_ds_mla(
124
reason="FlashMLASparseBackend requires CUDA 9.0 or higher",
125
)
126
def test_sparse_backend_decode_correctness(
127
- dist_init, batch_name, kv_cache_dtype, tensor_parallel_size, workspace_init
127
+ default_vllm_config,
128
+ dist_init,
129
+ batch_name,
130
+ kv_cache_dtype,
131
+ tensor_parallel_size,
132
+ workspace_init,
133
):
134
if current_platform.is_rocm():
135
pytest.skip("ROCm does not support fp8_ds_mla data type for kv cache.")
tests/v1/determinism/test_rms_norm_batch_invariant.py
+12
-6
@@ -21,7 +21,11 @@ from vllm.model_executor.layers.layernorm import RMSNorm
21
@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16])
22
@pytest.mark.parametrize("eps", [1e-6, 1e-5])
23
def test_rms_norm_batch_invariant_vs_standard(
24
- batch_size: int, hidden_size: int, dtype: torch.dtype, eps: float
24
+ default_vllm_config,
25
+ batch_size: int,
26
+ hidden_size: int,
27
+ dtype: torch.dtype,
28
+ eps: float,
29
):
30
"""
31
Compare batch-invariant Triton RMS norm against standard CUDA implementation.
@@ -68,7 +72,9 @@ def test_rms_norm_batch_invariant_vs_standard(
72
@pytest.mark.parametrize("batch_size", [1, 16, 128])
73
@pytest.mark.parametrize("seq_len", [1, 32, 512])
74
@pytest.mark.parametrize("hidden_size", [2048, 4096])
71
-def test_rms_norm_3d_input(batch_size: int, seq_len: int, hidden_size: int):
75
+def test_rms_norm_3d_input(
76
+ default_vllm_config, batch_size: int, seq_len: int, hidden_size: int
77
+):
78
"""
79
Test RMS norm with 3D input tensors (batch, seq_len, hidden_size).
80
@@ -107,7 +113,7 @@ def test_rms_norm_3d_input(batch_size: int, seq_len: int, hidden_size: int):
113
114
115
@skip_unsupported
110
-def test_rms_norm_numerical_stability():
116
+def test_rms_norm_numerical_stability(default_vllm_config):
117
"""
118
Test RMS norm numerical stability with extreme values.
119
@@ -167,7 +173,7 @@ def test_rms_norm_numerical_stability():
173
174
175
@skip_unsupported
170
-def test_rms_norm_formula():
176
+def test_rms_norm_formula(default_vllm_config):
177
"""
178
Test that RMS norm follows the correct mathematical formula.
179
@@ -201,7 +207,7 @@ def test_rms_norm_formula():
207
208
@skip_unsupported
209
@pytest.mark.parametrize("hidden_size", [128, 1024, 4096, 16384])
204
-def test_rms_norm_different_hidden_sizes(hidden_size: int):
210
+def test_rms_norm_different_hidden_sizes(default_vllm_config, hidden_size: int):
211
"""
212
Test RMS norm with various hidden sizes to ensure block size handling.
213
@@ -238,7 +244,7 @@ def test_rms_norm_different_hidden_sizes(hidden_size: int):
244
245
246
@skip_unsupported
241
-def test_rms_norm_determinism():
247
+def test_rms_norm_determinism(default_vllm_config):
248
"""
249
Test that batch-invariant RMS norm produces deterministic results.
250
tests/v1/kv_connector/unit/test_nixl_connector.py
+93
-83
@@ -299,6 +299,7 @@ def test_prompt_less_than_block_size():
299
)
300
def test_kv_transfer_handshake(dist_init):
301
"""Unit test for basic NixlConnector interface functionality."""
302
+ from vllm.config import set_current_vllm_config
303
304
# Test setup, we creates a scheduler that contains a NixlConnector
305
# of role SCHEDULER, and expect it to be serving NixlAgentMetadata from
@@ -308,81 +309,82 @@ def test_kv_transfer_handshake(dist_init):
309
vllm_config.kv_transfer_config.kv_buffer_device = "cpu"
310
scheduler = create_scheduler(vllm_config)
311
311
- # Create two NixlConnector of role WORKER, one is the worker of
312
- # the scheduler (prefill), the other is a worker of decode instance.
312
+ with set_current_vllm_config(vllm_config):
313
+ # Create two NixlConnector of role WORKER, one is the worker of
314
+ # the scheduler (prefill), the other is a worker of decode instance.
315
314
- # Prefill connector will register KV cache to populate proper handshake
315
- # metadata.
316
- prefill_connector = NixlConnector(vllm_config, KVConnectorRole.WORKER)
317
- kv_cache_shape = FlashAttentionBackend.get_kv_cache_shape(
318
- num_blocks=2, block_size=16, num_kv_heads=4, head_size=64
319
- )
320
- shared_tensor = torch.zeros(*kv_cache_shape, dtype=torch.float16)
321
- unique_tensor = torch.zeros(*kv_cache_shape, dtype=torch.float16)
322
- kv_caches = {
323
- "layer0": shared_tensor,
324
- "layer1": unique_tensor,
325
- "layer2": shared_tensor,
326
- }
327
- prefill_connector.register_kv_caches(kv_caches)
328
-
329
- # Simulate EngineCore initialization that would gather connector
330
- # metadata from all workers
331
- metadata = prefill_connector.get_handshake_metadata()
332
-
333
- # metadata is a NixlHandshakePayload, decode it to get NixlAgentMetadata
334
- decoder = msgspec.msgpack.Decoder(NixlAgentMetadata)
335
- expected_agent_metadata = decoder.decode(metadata.agent_metadata_bytes)
336
-
337
- # The scheduler connector expects metadata to be in
338
- # dict[int, KVConnectorHandshakeMetadata], where the first key is
339
- # the dp_rank, the second key is the tp_rank.
340
- scheduler_connector = scheduler.get_kv_connector()
341
- scheduler_connector.set_xfer_handshake_metadata({0: metadata})
342
-
343
- # Simulate a request that finishes prefill, which returns
344
- # corresponding NixlConnectorMetadata for decode instance.
345
- BLOCK_SIZE = vllm_config.cache_config.block_size
346
- NUM_EXTERNAL_FULL_BLOCKS = 2
347
- NUM_TOKENS = int(BLOCK_SIZE * (NUM_EXTERNAL_FULL_BLOCKS + 0.5))
348
-
349
- request = create_request(
350
- request_id=1,
351
- block_size=BLOCK_SIZE,
352
- num_tokens=NUM_TOKENS,
353
- do_remote_decode=True,
354
- )
355
- request.status = RequestStatus.FINISHED_LENGTH_CAPPED
356
- delay, kv_connector_metadata = scheduler.get_kv_connector().request_finished(
357
- request, [0, 1, 2]
358
- )
359
- assert delay
360
-
361
- # Decode connector will be able to create handshake with the prefill connector.
362
- decode_connector = NixlConnector(vllm_config, KVConnectorRole.WORKER)
363
-
364
- # Here we are testing the retrieval of NIXLAgentMetadata.
365
- # Knowing the implementation detail, we override the add_remote_agent
366
- # to validate the metadata received is the same as the one in prefill_connector.
367
- with patch.object(
368
- decode_connector.connector_worker, "add_remote_agent"
369
- ) as mock_add_remote_agent:
370
- mock_add_remote_agent.return_type = "remote_agent"
371
-
372
- decode_connector.connector_worker._nixl_handshake(
373
- kv_connector_metadata["remote_host"],
374
- kv_connector_metadata["remote_port"],
375
- kv_connector_metadata["tp_size"],
376
- kv_connector_metadata["remote_engine_id"],
316
+ # Prefill connector will register KV cache to populate proper handshake
317
+ # metadata.
318
+ prefill_connector = NixlConnector(vllm_config, KVConnectorRole.WORKER)
319
+ kv_cache_shape = FlashAttentionBackend.get_kv_cache_shape(
320
+ num_blocks=2, block_size=16, num_kv_heads=4, head_size=64
321
)
322
+ shared_tensor = torch.zeros(*kv_cache_shape, dtype=torch.float16)
323
+ unique_tensor = torch.zeros(*kv_cache_shape, dtype=torch.float16)
324
+ kv_caches = {
325
+ "layer0": shared_tensor,
326
+ "layer1": unique_tensor,
327
+ "layer2": shared_tensor,
328
+ }
329
+ prefill_connector.register_kv_caches(kv_caches)
330
+
331
+ # Simulate EngineCore initialization that would gather connector
332
+ # metadata from all workers
333
+ metadata = prefill_connector.get_handshake_metadata()
334
+
335
+ # metadata is a NixlHandshakePayload, decode it to get NixlAgentMetadata
336
+ decoder = msgspec.msgpack.Decoder(NixlAgentMetadata)
337
+ expected_agent_metadata = decoder.decode(metadata.agent_metadata_bytes)
338
+
339
+ # The scheduler connector expects metadata to be in
340
+ # dict[int, KVConnectorHandshakeMetadata], where the first key is
341
+ # the dp_rank, the second key is the tp_rank.
342
+ scheduler_connector = scheduler.get_kv_connector()
343
+ scheduler_connector.set_xfer_handshake_metadata({0: metadata})
344
+
345
+ # Simulate a request that finishes prefill, which returns
346
+ # corresponding NixlConnectorMetadata for decode instance.
347
+ BLOCK_SIZE = vllm_config.cache_config.block_size
348
+ NUM_EXTERNAL_FULL_BLOCKS = 2
349
+ NUM_TOKENS = int(BLOCK_SIZE * (NUM_EXTERNAL_FULL_BLOCKS + 0.5))
350
+
351
+ request = create_request(
352
+ request_id=1,
353
+ block_size=BLOCK_SIZE,
354
+ num_tokens=NUM_TOKENS,
355
+ do_remote_decode=True,
356
+ )
357
+ request.status = RequestStatus.FINISHED_LENGTH_CAPPED
358
+ delay, kv_connector_metadata = scheduler.get_kv_connector().request_finished(
359
+ request, [0, 1, 2]
360
+ )
361
+ assert delay
362
+
363
+ # Decode connector will be able to create handshake with the prefill connector.
364
+ decode_connector = NixlConnector(vllm_config, KVConnectorRole.WORKER)
365
+
366
+ # Here we are testing the retrieval of NIXLAgentMetadata.
367
+ # Knowing the implementation detail, we override the add_remote_agent
368
+ # to validate the metadata received is the same as the one in prefill_connector.
369
+ with patch.object(
370
+ decode_connector.connector_worker, "add_remote_agent"
371
+ ) as mock_add_remote_agent:
372
+ mock_add_remote_agent.return_type = "remote_agent"
373
+
374
+ decode_connector.connector_worker._nixl_handshake(
375
+ kv_connector_metadata["remote_host"],
376
+ kv_connector_metadata["remote_port"],
377
+ kv_connector_metadata["tp_size"],
378
+ kv_connector_metadata["remote_engine_id"],
379
+ )
380
379
- received_metadata = mock_add_remote_agent.call_args.args
380
- assert received_metadata[0] == expected_agent_metadata
381
- assert received_metadata[1] == 0 # remote_tp_rank
382
- assert received_metadata[2] == 1 # remote_tp_size
381
+ received_metadata = mock_add_remote_agent.call_args.args
382
+ assert received_metadata[0] == expected_agent_metadata
383
+ assert received_metadata[1] == 0 # remote_tp_rank
384
+ assert received_metadata[2] == 1 # remote_tp_size
385
384
- # Need to shutdown the background thread to release NIXL side channel port
385
- scheduler_connector.shutdown()
386
+ # Need to shutdown the background thread to release NIXL side channel port
387
+ scheduler_connector.shutdown()
388
389
390
class FakeNixlConnectorWorker(NixlConnectorWorker):
@@ -458,6 +460,7 @@ class TestNixlHandshake:
460
)
461
def test_multi_xfer_one_engine(
462
self,
463
+ default_vllm_config,
464
# dist_init is a fixture that initializes the distributed environment.
465
dist_init,
466
):
@@ -547,6 +550,7 @@ class TestNixlHandshake:
550
)
551
def test_async_load_kv(
552
self,
553
+ default_vllm_config,
554
# Fixture that initializes the distributed environment.
555
dist_init,
556
# Simulate consumer-producer TP sizes.
@@ -605,7 +609,7 @@ class TestNixlHandshake:
609
)
610
@pytest.mark.parametrize("local_tp_size", [1, 2])
611
def test_prefill_tp_size_greater_than_decode_tp_size(
608
- self, local_tp_size: int, dist_init
612
+ self, local_tp_size: int, default_vllm_config, dist_init
613
):
614
"""
615
Verify remote TP > local TP handshake succeeds with different
@@ -670,7 +674,7 @@ class TestNixlHandshake:
674
)
675
@pytest.mark.parametrize("local_tp_size", [1, 2])
676
def test_prefill_tp_size_greater_than_decode_tp_size_mla(
673
- self, local_tp_size: int, dist_init
677
+ self, local_tp_size: int, default_vllm_config, dist_init
678
):
679
"""
680
Verify remote TP > local TP handshake succeeds with different
@@ -770,6 +774,7 @@ class TestNixlHandshake:
774
)
775
def test_concurrent_load_kv(
776
self,
777
+ default_vllm_config,
778
# dist_init is a fixture that initializes the distributed environment.
779
dist_init,
780
):
@@ -830,7 +835,9 @@ class TestNixlHandshake:
835
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
836
FakeNixlWrapper,
837
)
833
- def test_handshake_fails_on_kv_cache_layout_mismatch(self, dist_init):
838
+ def test_handshake_fails_on_kv_cache_layout_mismatch(
839
+ self, default_vllm_config, dist_init
840
+ ):
841
"""
842
Verify that adding a remote agent fails if kv_cache_layout differs.
843
This test is only relevant for heterogeneous TP.
@@ -879,7 +886,7 @@ class TestNixlHandshake:
886
FakeNixlWrapper,
887
)
888
def test_handshake_succeed_on_kv_cache_layout_mismatch_with_experimental(
882
- self, dist_init
889
+ self, default_vllm_config, dist_init
890
):
891
"""
892
Verify that adding a remote agent fails if kv_cache_layout differs.
@@ -934,7 +941,7 @@ class TestNixlHandshake:
941
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
942
FakeNixlWrapper,
943
)
937
-def test_kv_connector_stats(dist_init):
944
+def test_kv_connector_stats(default_vllm_config, dist_init):
945
"""Test that KV transfer stats are properly recorded and retrieved."""
946
vllm_config = create_vllm_config()
947
@@ -1357,7 +1364,7 @@ def _run_abort_timeout_test(llm: LLM, timeout: int):
1364
"TRITON_ATTN",
1365
],
1366
)
1360
-def test_register_kv_caches(dist_init, attn_backend):
1367
+def test_register_kv_caches(default_vllm_config, dist_init, attn_backend):
1368
"""
1369
Test that register_kv_caches() properly calls nixl_wrapper methods with
1370
correct data.
@@ -1518,7 +1525,9 @@ class FakePlatform(Platform):
1525
("oot", "VRAM"),
1526
],
1527
)
1521
-def test_kv_buffer_to_nixl_memory_types(dist_init, kv_buffer_device, nixl_memory_type):
1528
+def test_kv_buffer_to_nixl_memory_types(
1529
+ default_vllm_config, dist_init, kv_buffer_device, nixl_memory_type
1530
+):
1531
"""
1532
Test that register_kv_caches() passes the correct memory types from the
1533
config to the nixl_wrapper.
@@ -1563,7 +1572,7 @@ def test_kv_buffer_to_nixl_memory_types(dist_init, kv_buffer_device, nixl_memory
1572
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
1573
FakeNixlWrapper,
1574
)
1566
-def test_shutdown_cleans_up_resources(dist_init):
1575
+def test_shutdown_cleans_up_resources(default_vllm_config, dist_init):
1576
"""Test that shutdown() properly cleans up all resources."""
1577
vllm_config = create_vllm_config()
1578
@@ -1622,7 +1631,7 @@ def test_shutdown_cleans_up_resources(dist_init):
1631
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
1632
FakeNixlWrapper,
1633
)
1625
-def test_aborted_request_removed_from_worker_in_batch(dist_init):
1634
+def test_aborted_request_removed_from_worker_in_batch(default_vllm_config, dist_init):
1635
"""
1636
Create and schedule a request so that P adds it to in-batch tracking via
1637
the real scheduler, then simulate an abort (request not in next scheduler
@@ -1731,7 +1740,7 @@ class FailingNixlWrapper(FakeNixlWrapper):
1740
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
1741
FailingNixlWrapper,
1742
)
1734
-def test_handshake_failure_returns_finished(dist_init):
1743
+def test_handshake_failure_returns_finished(default_vllm_config, dist_init):
1744
"""Test that handshake failures mark blocks invalid and return via get_finished."""
1745
vllm_config = create_vllm_config()
1746
@@ -1780,7 +1789,7 @@ def test_handshake_failure_returns_finished(dist_init):
1789
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
1790
FailingNixlWrapper,
1791
)
1783
-def test_transfer_setup_failure_returns_finished(dist_init):
1792
+def test_transfer_setup_failure_returns_finished(default_vllm_config, dist_init):
1793
"""Test that transfer setup failures mark blocks invalid
1794
and return via get_finished."""
1795
vllm_config = create_vllm_config()
@@ -1855,6 +1864,7 @@ def test_transfer_setup_failure_returns_finished(dist_init):
1864
FakeNixlWrapper,
1865
)
1866
def test_compatibility_hash_validation(
1867
+ default_vllm_config,
1868
dist_init,
1869
mismatch_type,
1870
config_overrides,
@@ -1967,7 +1977,7 @@ def test_compatibility_hash_validation(
1977
"vllm.distributed.kv_transfer.kv_connector.v1.nixl_connector.NixlWrapper",
1978
FakeNixlWrapper,
1979
)
1970
-def test_handshake_decode_errors(dist_init, error_scenario):
1980
+def test_handshake_decode_errors(default_vllm_config, dist_init, error_scenario):
1981
"""
1982
Test that msgspec decode errors are properly handled during handshake.
1983
tests/v1/kv_offload/test_cpu_gpu.py
+1
@@ -50,6 +50,7 @@ NUM_MAPPINGS = [3]
50
@pytest.mark.parametrize("device", CUDA_DEVICES)
51
@torch.inference_mode()
52
def test_transfer(
53
+ default_vllm_config,
54
gpu_to_cpu: bool,
55
num_mappings: int,
56
head_size: int,
tests/v1/worker/test_gpu_model_runner.py
+16
-15
@@ -112,15 +112,16 @@ def get_vllm_config():
112
@pytest.fixture
113
def model_runner():
114
vllm_config = get_vllm_config()
115
- model_config = vllm_config.model_config
116
- num_heads = model_config.get_num_kv_heads(vllm_config.parallel_config)
117
- head_size = model_config.get_head_size()
118
- vllm_config.compilation_config.static_forward_context["layer.0"] = Attention(
119
- num_heads, head_size, 0.1
120
- )
121
- runner = GPUModelRunner(vllm_config, DEVICE)
122
- initialize_kv_cache(runner)
123
- return runner
115
+ with set_current_vllm_config(vllm_config):
116
+ model_config = vllm_config.model_config
117
+ num_heads = model_config.get_num_kv_heads(vllm_config.parallel_config)
118
+ head_size = model_config.get_head_size()
119
+ vllm_config.compilation_config.static_forward_context["layer.0"] = Attention(
120
+ num_heads, head_size, 0.1
121
+ )
122
+ runner = GPUModelRunner(vllm_config, DEVICE)
123
+ initialize_kv_cache(runner)
124
+ yield runner
125
126
127
model_runner_2 = model_runner
@@ -546,7 +547,7 @@ def test_reload_weights_before_load_model(model_runner):
547
model_runner.reload_weights()
548
549
549
-def test_init_kv_cache_with_kv_sharing_invalid_target_layer_order():
550
+def test_init_kv_cache_with_kv_sharing_invalid_target_layer_order(default_vllm_config):
551
torch.set_default_dtype(torch.float16)
552
layer_0 = "model.layers.0.self_attn.attn"
553
layer_1 = "model.layers.1.self_attn.attn"
@@ -573,7 +574,7 @@ def test_init_kv_cache_with_kv_sharing_invalid_target_layer_order():
574
assert fwd_context is not None
575
576
576
-def test_init_kv_cache_with_kv_sharing_target_layer_not_exist():
577
+def test_init_kv_cache_with_kv_sharing_target_layer_not_exist(default_vllm_config):
578
torch.set_default_dtype(torch.float16)
579
layer_0 = "model.layers.0.self_attn.attn"
580
layer_1 = "model.layers.1.self_attn.attn"
@@ -600,7 +601,7 @@ def test_init_kv_cache_with_kv_sharing_target_layer_not_exist():
601
assert fwd_context is not None
602
603
603
-def test_init_kv_cache_with_kv_sharing_target_same_as_current():
604
+def test_init_kv_cache_with_kv_sharing_target_same_as_current(default_vllm_config):
605
torch.set_default_dtype(torch.float16)
606
layer_0 = "model.layers.0.self_attn.attn"
607
layer_1 = "model.layers.1.self_attn.attn"
@@ -627,7 +628,7 @@ def test_init_kv_cache_with_kv_sharing_target_same_as_current():
628
assert fwd_context is not None
629
630
630
-def test_init_kv_cache_without_kv_sharing():
631
+def test_init_kv_cache_without_kv_sharing(default_vllm_config):
632
torch.set_default_dtype(torch.float16)
633
layer_0 = "model.layers.0.self_attn.attn"
634
layer_1 = "model.layers.1.self_attn.attn"
@@ -694,7 +695,7 @@ def test_init_kv_cache_without_kv_sharing():
695
assert kv_cache_config.kv_cache_groups[0].layer_names[1] == layer_1
696
697
697
-def test_init_kv_cache_with_kv_sharing_valid():
698
+def test_init_kv_cache_with_kv_sharing_valid(default_vllm_config):
699
torch.set_default_dtype(torch.float16)
700
layer_0 = "model.layers.0.self_attn.attn"
701
layer_1 = "model.layers.1.self_attn.attn"
@@ -1047,7 +1048,7 @@ def test_input_batch_with_kernel_block_sizes():
1048
assert block_table.block_size == kernel_size
1049
1050
1050
-def test_hybrid_cache_integration(model_runner, dist_init):
1051
+def test_hybrid_cache_integration(default_vllm_config, dist_init):
1052
"""Test hybrid cache architecture integration with GPUModelRunner."""
1053
# Create a new model runner with hybrid cache configuration
1054
vllm_config = get_vllm_config()
tests/v1/worker/test_utils.py
+8
-8
@@ -6,14 +6,14 @@ import torch
6
from vllm.v1.worker.utils import bind_kv_cache
7
8
9
-def test_bind_kv_cache():
9
+def test_bind_kv_cache(default_vllm_config):
10
from vllm.attention.layer import Attention
11
12
ctx = {
13
- "layers.0.self_attn": Attention(32, 128, 0.1),
14
- "layers.1.self_attn": Attention(32, 128, 0.1),
15
- "layers.2.self_attn": Attention(32, 128, 0.1),
16
- "layers.3.self_attn": Attention(32, 128, 0.1),
13
+ "layers.0.self_attn": Attention(32, 128, 0.1, prefix="layers.0.self_attn"),
14
+ "layers.1.self_attn": Attention(32, 128, 0.1, prefix="layers.1.self_attn"),
15
+ "layers.2.self_attn": Attention(32, 128, 0.1, prefix="layers.2.self_attn"),
16
+ "layers.3.self_attn": Attention(32, 128, 0.1, prefix="layers.3.self_attn"),
17
}
18
kv_cache = {
19
"layers.0.self_attn": torch.zeros((1,)),
@@ -34,13 +34,13 @@ def test_bind_kv_cache():
34
assert runner_kv_caches[3] is kv_cache["layers.3.self_attn"]
35
36
37
-def test_bind_kv_cache_non_attention():
37
+def test_bind_kv_cache_non_attention(default_vllm_config):
38
from vllm.attention.layer import Attention
39
40
# example from Jamba PP=2
41
ctx = {
42
- "model.layers.20.attn": Attention(32, 128, 0.1),
43
- "model.layers.28.attn": Attention(32, 128, 0.1),
42
+ "model.layers.20.attn": Attention(32, 128, 0.1, prefix="model.layers.20.attn"),
43
+ "model.layers.28.attn": Attention(32, 128, 0.1, prefix="model.layers.28.attn"),
44
}
45
kv_cache = {
46
"model.layers.20.attn": torch.zeros((1,)),
vllm/attention/utils/fa_utils.py
+6
-3
@@ -59,10 +59,13 @@ def get_flash_attn_version(requires_alibi: bool = False) -> int | None:
59
)
60
61
# 2. override if passed by environment or config
62
- from vllm.config import get_current_vllm_config
62
+ from vllm.config import get_current_vllm_config_or_none
63
64
- vllm_config = get_current_vllm_config()
65
- if vllm_config.attention_config.flash_attn_version is not None:
64
+ vllm_config = get_current_vllm_config_or_none()
65
+ if (
66
+ vllm_config is not None
67
+ and vllm_config.attention_config.flash_attn_version is not None
68
+ ):
69
fa_version = vllm_config.attention_config.flash_attn_version
70
71
# 3. fallback for unsupported combinations
vllm/config/__init__.py
+2
@@ -42,6 +42,7 @@ from vllm.config.vllm import (
42
VllmConfig,
43
get_cached_compilation_config,
44
get_current_vllm_config,
45
+ get_current_vllm_config_or_none,
46
get_layers_from_vllm_config,
47
set_current_vllm_config,
48
)
@@ -105,6 +106,7 @@ __all__ = [
106
"VllmConfig",
107
"get_cached_compilation_config",
108
"get_current_vllm_config",
109
+ "get_current_vllm_config_or_none",
110
"set_current_vllm_config",
111
"get_layers_from_vllm_config",
112
]
vllm/config/vllm.py
+12
-7
@@ -1441,13 +1441,18 @@ def get_cached_compilation_config():
1441
1442
def get_current_vllm_config() -> VllmConfig:
1443
if _current_vllm_config is None:
1444
- # in ci, usually when we test custom ops/modules directly,
1445
- # we don't set the vllm config. In that case, we set a default
1446
- # config.
1447
- # Use stack level 2 so the log contains the line of the caller,
1448
- # so it's easier to track down the source of the warning.
1449
- logger.warning("Current vLLM config is not set.", stacklevel=2)
1450
- return VllmConfig()
1444
+ raise AssertionError(
1445
+ "Current vLLM config is not set. This typically means "
1446
+ "get_current_vllm_config() was called outside of a "
1447
+ "set_current_vllm_config() context, or a CustomOp was instantiated "
1448
+ "at module import time or model forward time when config is not set. "
1449
+ "For tests that directly test custom ops/modules, use the "
1450
+ "'default_vllm_config' pytest fixture from tests/conftest.py."
1451
+ )
1452
+ return _current_vllm_config
1453
+
1454
+
1455
+def get_current_vllm_config_or_none() -> VllmConfig | None:
1456
return _current_vllm_config
1457
1458
vllm/distributed/device_communicators/base_device_communicator.py
+2
-2
@@ -117,9 +117,9 @@ class DeviceCommunicatorBase:
117
118
use_ep = False
119
all2all_backend = None
120
- from vllm.config import get_current_vllm_config
120
+ from vllm.config import get_current_vllm_config_or_none
121
122
- config = get_current_vllm_config()
122
+ config = get_current_vllm_config_or_none()
123
if config is not None:
124
# as long as we use data parallel (coupled data parallel
125
# where all data parallel ranks execute forward together),
vllm/distributed/device_communicators/quick_all_reduce.py
+2
-2
@@ -9,7 +9,7 @@ from torch.distributed import ProcessGroup
9
10
import vllm.envs as envs
11
from vllm import _custom_ops as ops
12
-from vllm.config import get_current_vllm_config
12
+from vllm.config import get_current_vllm_config_or_none
13
from vllm.distributed.parallel_state import in_the_same_node_as
14
from vllm.logger import init_logger
15
from vllm.platforms import current_platform
@@ -184,7 +184,7 @@ class QuickAllReduce:
184
)
185
return
186
self.qr_quant_level = QuickReduceRegime[regime_str]
187
- vllm_config = get_current_vllm_config()
187
+ vllm_config = get_current_vllm_config_or_none()
188
if (
189
vllm_config is not None
190
and hasattr(vllm_config, "model_config")
vllm/distributed/parallel_state.py
+6
-6
@@ -1177,9 +1177,9 @@ def init_distributed_environment(
1177
distributed_init_method,
1178
backend,
1179
)
1180
- from vllm.config import get_current_vllm_config
1180
+ from vllm.config import get_current_vllm_config_or_none
1181
1182
- config = get_current_vllm_config()
1182
+ config = get_current_vllm_config_or_none()
1183
if (
1184
config is not None
1185
and config.parallel_config.distributed_executor_backend != "external_launcher"
@@ -1251,7 +1251,7 @@ def init_distributed_environment(
1251
if _WORLD is None:
1252
ranks = list(range(torch.distributed.get_world_size()))
1253
_WORLD = init_world_group(ranks, local_rank, backend)
1254
- if config.parallel_config.nnodes > 1:
1254
+ if config is not None and config.parallel_config.nnodes > 1:
1255
_NODE_COUNT = config.parallel_config.nnodes
1256
else:
1257
_NODE_COUNT = _node_count(_WORLD.cpu_group)
@@ -1260,7 +1260,7 @@ def init_distributed_environment(
1260
assert _WORLD.world_size == torch.distributed.get_world_size(), (
1261
"world group already initialized with a different world size"
1262
)
1263
- if config.parallel_config.nnodes_within_dp > 1:
1263
+ if config is not None and config.parallel_config.nnodes_within_dp > 1:
1264
if parallel_config.data_parallel_size > 1:
1265
world_size_inner_dp = parallel_config.world_size
1266
group_ranks = [
@@ -1316,9 +1316,9 @@ def initialize_model_parallel(
1316
backend = backend or torch.distributed.get_backend(get_world_group().device_group)
1317
1318
data_parallel_size = 1
1319
- from vllm.config import get_current_vllm_config
1319
+ from vllm.config import get_current_vllm_config_or_none
1320
1321
- config = get_current_vllm_config()
1321
+ config = get_current_vllm_config_or_none()
1322
if config is not None:
1323
data_parallel_size = config.parallel_config.data_parallel_size
1324
vllm/model_executor/layers/fused_moe/cpu_fused_moe.py
+23
-5
@@ -13,10 +13,28 @@ from vllm.model_executor.layers.quantization.utils.layer_utils import replace_pa
13
from vllm.utils.torch_utils import direct_register_custom_op
14
15
_CPU_MOE_LAYER_CACHE = {}
16
-_CPU_MOE_ACT = {
17
- "silu": SiluAndMul(),
18
- "swigluoai": SwigluOAIAndMul(),
19
-}
16
+
17
+
18
+class _LazyActivationDict(dict):
19
+ """Lazily instantiate activation functions on first access.
20
+
21
+ Avoids triggering CustomOp.__init__() at module import time,
22
+ which would call get_current_vllm_config() before config is set.
23
+ """
24
+
25
+ _factories: dict[str, type[SiluAndMul] | type[SwigluOAIAndMul]] = {
26
+ "silu": SiluAndMul,
27
+ "swigluoai": SwigluOAIAndMul,
28
+ }
29
+
30
+ def __missing__(self, key: str) -> SiluAndMul | SwigluOAIAndMul:
31
+ if key not in self._factories:
32
+ raise KeyError(f"{key} is not a supported activation")
33
+ self[key] = self._factories[key]()
34
+ return self[key]
35
+
36
+
37
+_CPU_MOE_ACT = _LazyActivationDict()
38
39
40
def grouped_topk(
@@ -212,7 +230,7 @@ class CPUFusedMOE:
230
apply_router_weight_on_input: bool = False,
231
activation: str = "silu",
232
) -> torch.Tensor:
215
- assert activation in _CPU_MOE_ACT, f"{activation} is not supported."
233
+ assert activation in _CPU_MOE_ACT._factories, f"{activation} is not supported."
234
assert not apply_router_weight_on_input
235
236
topk_weights, topk_ids = select_experts(
vllm/model_executor/layers/fused_moe/layer.py
+16
-13
@@ -540,6 +540,20 @@ class FusedMoE(CustomOp):
540
self.apply_router_weight_on_input = apply_router_weight_on_input
541
self.activation = activation
542
543
+ self._grouped_topk_impl: GroupedTopk | None = None
544
+ if self.use_grouped_topk:
545
+ assert self.num_expert_group is not None
546
+ assert self.topk_group is not None
547
+ self._grouped_topk_impl = GroupedTopk(
548
+ topk=self.top_k,
549
+ renormalize=self.renormalize,
550
+ num_expert_group=self.num_expert_group,
551
+ topk_group=self.topk_group,
552
+ scoring_func=self.scoring_func,
553
+ routed_scaling_factor=self.routed_scaling_factor,
554
+ num_fused_shared_experts=self.num_fused_shared_experts,
555
+ )
556
+
557
if self.scoring_func != "softmax" and not self.use_grouped_topk:
558
raise ValueError(
559
"Only softmax scoring function is supported for non-grouped topk."
@@ -1588,19 +1602,8 @@ class FusedMoE(CustomOp):
1602
1603
# DeepSeekv2 uses grouped_top_k
1604
elif self.use_grouped_topk and valid_grouping():
1591
- assert self.topk_group is not None
1592
- assert self.num_expert_group is not None
1593
- grouped_topk_impl = GroupedTopk(
1594
- topk=self.top_k,
1595
- renormalize=self.renormalize,
1596
- num_expert_group=self.num_expert_group,
1597
- topk_group=self.topk_group,
1598
- scoring_func=self.scoring_func,
1599
- routed_scaling_factor=self.routed_scaling_factor,
1600
- num_fused_shared_experts=self.num_fused_shared_experts,
1601
- )
1602
-
1603
- topk_weights, topk_ids = grouped_topk_impl(
1605
+ assert self._grouped_topk_impl is not None
1606
+ topk_weights, topk_ids = self._grouped_topk_impl(
1607
hidden_states=hidden_states,
1608
gating_output=router_logits,
1609
e_score_correction_bias=self.e_score_correction_bias,
vllm/model_executor/models/keye.py
+7
-6
@@ -339,15 +339,11 @@ def apply_rotary_pos_emb_flashatt(
339
k: torch.Tensor,
340
cos: torch.Tensor,
341
sin: torch.Tensor,
342
+ apply_rotary_emb: ApplyRotaryEmb,
343
) -> tuple[torch.Tensor, torch.Tensor]:
344
cos = cos.chunk(2, dim=-1)[0].contiguous()
345
sin = sin.chunk(2, dim=-1)[0].contiguous()
346
346
- apply_rotary_emb = ApplyRotaryEmb(
347
- enforce_enable=True,
348
- enable_fp32_compute=True,
349
- )
350
-
347
q_embed = apply_rotary_emb(q, cos, sin)
348
k_embed = apply_rotary_emb(k, cos, sin)
349
@@ -410,6 +406,11 @@ class KeyeSiglipAttention(nn.Module):
406
multimodal_config=multimodal_config,
407
)
408
409
+ self.apply_rotary_emb = ApplyRotaryEmb(
410
+ enforce_enable=True,
411
+ enable_fp32_compute=True,
412
+ )
413
+
414
def forward(
415
self,
416
hidden_states: torch.Tensor,
@@ -448,7 +449,7 @@ class KeyeSiglipAttention(nn.Module):
449
self.num_kv_heads,
450
self.head_dim,
451
)
451
- q, k = apply_rotary_pos_emb_flashatt(q, k, cos, sin)
452
+ q, k = apply_rotary_pos_emb_flashatt(q, k, cos, sin, self.apply_rotary_emb)
453
v = v.view(
454
*v.shape[:-1],
455
self.num_kv_heads,
vllm/model_executor/models/siglip2navit.py
+8
-6
@@ -152,16 +152,12 @@ def apply_rotary_pos_emb(
152
k: torch.Tensor,
153
cos: torch.Tensor,
154
sin: torch.Tensor,
155
- is_flash_attn_backend: bool = False,
155
+ is_flash_attn_backend: bool,
156
+ apply_rotary_emb: ApplyRotaryEmb,
157
) -> tuple[torch.Tensor, torch.Tensor]:
158
cos = cos.chunk(2, dim=-1)[0].contiguous()
159
sin = sin.chunk(2, dim=-1)[0].contiguous()
160
160
- apply_rotary_emb = ApplyRotaryEmb(
161
- enforce_enable=True,
162
- enable_fp32_compute=True,
163
- )
164
-
161
if is_flash_attn_backend and current_platform.is_cuda():
162
apply_rotary_emb_func = apply_rotary_emb.forward_cuda
163
elif is_flash_attn_backend and current_platform.is_rocm():
@@ -235,6 +231,11 @@ class Siglip2Attention(nn.Module):
231
multimodal_config=multimodal_config,
232
)
233
234
+ self.apply_rotary_emb = ApplyRotaryEmb(
235
+ enforce_enable=True,
236
+ enable_fp32_compute=True,
237
+ )
238
+
239
def forward(
240
self,
241
hidden_states: torch.Tensor,
@@ -260,6 +261,7 @@ class Siglip2Attention(nn.Module):
261
cos,
262
sin,
263
self.attn.is_flash_attn_backend,
264
+ self.apply_rotary_emb,
265
)
266
queries = queries.squeeze(0)
267
keys = keys.squeeze(0)
vllm/v1/worker/gpu_worker.py
+4
-2
@@ -14,7 +14,7 @@ import torch.distributed
14
import torch.nn as nn
15
16
import vllm.envs as envs
17
-from vllm.config import CUDAGraphMode, VllmConfig
17
+from vllm.config import CUDAGraphMode, VllmConfig, set_current_vllm_config
18
from vllm.config.compilation import CompilationMode
19
from vllm.distributed import (
20
ensure_model_parallel_initialized,
@@ -268,7 +268,9 @@ class Worker(WorkerBase):
268
# to hijack tensor allocation.
269
def load_model(self) -> None:
270
eep_scale_up = os.environ.get("VLLM_ELASTIC_EP_SCALE_UP_LAUNCH") == "1"
271
- with self._maybe_get_memory_pool_context(tag="weights"):
271
+ with self._maybe_get_memory_pool_context(
272
+ tag="weights"
273
+ ) and set_current_vllm_config(self.vllm_config):
274
self.model_runner.load_model(eep_scale_up=eep_scale_up)
275
276
def update_config(self, overrides: dict[str, Any]) -> None: