main
py 159 lines 4.99 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from types import SimpleNamespace
5 from typing import Any
6
7 import pytest
8
9 from vllm.config import AuxOutputConfig, VllmConfig
10 from vllm.config.kv_transfer import KVRole, KVTransferConfig
11 from vllm.engine.arg_utils import EngineArgs
12
13 pytestmark = pytest.mark.cpu_test
14
15
16 def _config(
17 *,
18 use_v2: bool = True,
19 pp: int = 1,
20 dcp: int = 1,
21 pcp: int = 1,
22 connector: str | None = None,
23 kv_role: KVRole = "kv_both",
24 runner_type: str = "generate",
25 is_moe: bool = True,
26 sliding_window: int | None = None,
27 attention_chunk_size: int | None = None,
28 enable_prefix_caching: bool = True,
29 adaptive_verification: bool = False,
30 ):
31 return SimpleNamespace(
32 model_config=SimpleNamespace(
33 runner_type=runner_type,
34 is_moe=is_moe,
35 get_sliding_window=lambda: sliding_window,
36 attention_chunk_size=attention_chunk_size,
37 ),
38 use_v2_model_runner=use_v2,
39 parallel_config=SimpleNamespace(
40 pipeline_parallel_size=pp,
41 decode_context_parallel_size=dcp,
42 prefill_context_parallel_size=pcp,
43 ),
44 aux_output_config=AuxOutputConfig(enable_return_routed_experts=True),
45 cache_config=SimpleNamespace(
46 enable_prefix_caching=enable_prefix_caching,
47 ),
48 speculative_config=(
49 SimpleNamespace(enable_adaptive_verification=True)
50 if adaptive_verification
51 else None
52 ),
53 kv_transfer_config=(
54 None
55 if connector is None
56 else KVTransferConfig(
57 kv_connector=connector,
58 kv_role=kv_role,
59 )
60 ),
61 )
62
63
64 def test_aux_output_config_defaults():
65 config = AuxOutputConfig()
66
67 assert not config.enabled
68 assert not config.enable_return_routed_experts
69 assert config.max_bytes is None
70
71
72 def test_aux_output_capture_changes_compilation_hash():
73 disabled = AuxOutputConfig()
74 enabled = AuxOutputConfig(enable_return_routed_experts=True)
75
76 assert disabled.compute_hash() != enabled.compute_hash()
77
78
79 def test_legacy_routed_experts_flag_updates_aux_output_config():
80 args = EngineArgs(enable_return_routed_experts=True)
81
82 assert args.aux_output_config.enabled
83 assert args.aux_output_config.enable_return_routed_experts
84
85
86 @pytest.mark.parametrize(
87 ("kwargs", "error"),
88 [
89 ({"use_v2": False}, "requires Model Runner V2"),
90 ({"runner_type": "pooling"}, "only supports generate runners"),
91 ({"is_moe": False}, "only supports MoE models"),
92 ({"enable_prefix_caching": False}, "requires prefix caching"),
93 (
94 {"adaptive_verification": True},
95 "adaptive speculative verification",
96 ),
97 ({"pp": 2}, "pipeline parallelism"),
98 ({"dcp": 2}, "context parallelism"),
99 ({"pcp": 2}, "context parallelism"),
100 ],
101 )
102 def test_aux_output_connector_rejects_unsupported_configuration(kwargs, error):
103 with pytest.raises(ValueError, match=error):
104 VllmConfig._verify_aux_output_compatibility(_config(**kwargs))
105
106
107 @pytest.mark.parametrize(
108 ("connector", "blocked"),
109 [
110 ("NixlConnector", True),
111 ("NixlPullConnector", True),
112 ("NixlPushConnector", True),
113 ("MoRIIOConnector", True),
114 ("MooncakeConnector", True),
115 ("MooncakeStoreConnector", False),
116 ("OffloadingConnector", False),
117 ("LMCacheConnectorV1", False),
118 ("LMCacheMPConnector", False),
119 ("SimpleCPUOffloadConnector", False),
120 ],
121 )
122 @pytest.mark.parametrize("kv_role", ["kv_both", "kv_producer", "kv_consumer"])
123 @pytest.mark.parametrize("multi", [False, True])
124 def test_aux_output_connector_policy_is_independent_of_role(
125 connector, blocked, kv_role, multi
126 ):
127 config = _config(connector=connector, kv_role=kv_role)
128 if multi:
129 config.kv_transfer_config = KVTransferConfig(
130 kv_connector="MultiConnector",
131 kv_role=kv_role,
132 kv_connector_extra_config={
133 "connectors": [
134 {"kv_connector": "OffloadingConnector", "kv_role": "kv_both"},
135 {"kv_connector": connector, "kv_role": kv_role},
136 ]
137 },
138 )
139 if blocked:
140 with pytest.raises(ValueError, match=f"incompatible with {connector}"):
141 VllmConfig._verify_aux_output_compatibility(config)
142 else:
143 VllmConfig._verify_aux_output_compatibility(config)
144
145
146 @pytest.mark.parametrize(
147 "kwargs",
148 [{"sliding_window": 4096}, {"attention_chunk_size": 4096}],
149 )
150 def test_aux_output_config_defers_attention_layout_to_kv_config(kwargs):
151 VllmConfig._verify_aux_output_compatibility(_config(**kwargs))
152
153
154 def test_aux_output_guards_are_inactive_when_capture_is_disabled():
155 config: Any = VllmConfig.__new__(VllmConfig)
156 config.model_config = SimpleNamespace()
157 config.aux_output_config = AuxOutputConfig()
158
159 config._verify_aux_output_compatibility()