|
27 | 27 | global_kv_cache_config = KvCacheConfig(free_gpu_memory_fraction=0.4) |
28 | 28 |
|
29 | 29 |
|
30 | | -@pytest.fixture(scope="module") |
31 | | -def shared_mpi_session_2gpu(): |
32 | | - yield from _shared_mpi_session(2) |
33 | | - |
34 | | - |
35 | | -@pytest.fixture(scope="module") |
36 | | -def shared_mpi_session_4gpu(): |
37 | | - yield from _shared_mpi_session(4) |
38 | | - |
39 | | - |
40 | | -@pytest.fixture(scope="module") |
41 | | -def shared_llm_2gpu(shared_mpi_session_2gpu): |
42 | | - # Factory for tests that construct the LLM directly (see RPC tests below). |
43 | | - return _make_shared_llm(shared_mpi_session_2gpu) |
44 | | - |
45 | | - |
46 | | -@pytest.fixture(scope="module") |
47 | | -def mpi_kwargs_2gpu(shared_mpi_session_2gpu): |
48 | | - # Ready-to-spread LLM kwargs that inject the shared 2-GPU session (or {} when |
49 | | - # MPI is disabled). Harness-based tests just spread this; they never touch the |
50 | | - # raw session object. |
51 | | - return _mpi_session_kwargs(shared_mpi_session_2gpu) |
52 | | - |
53 | | - |
54 | | -@pytest.fixture(scope="module") |
55 | | -def mpi_kwargs_4gpu(shared_mpi_session_4gpu): |
56 | | - return _mpi_session_kwargs(shared_mpi_session_4gpu) |
57 | | - |
58 | | - |
59 | | -@pytest.mark.gpu2 |
60 | | -def test_llm_capture_request_error(mpi_kwargs_2gpu): |
61 | | - _test_llm_capture_request_error(pytorch_backend=True, |
62 | | - tp_size=2, |
63 | | - **mpi_kwargs_2gpu) |
64 | | - |
65 | | - |
66 | | -@pytest.mark.gpu4 |
67 | | -def test_tinyllama_logits_processor_tp2pp2(mpi_kwargs_4gpu): |
68 | | - tinyllama_logits_processor_test_harness(backend="pytorch", |
69 | | - tensor_parallel_size=2, |
70 | | - pipeline_parallel_size=2, |
71 | | - **mpi_kwargs_4gpu) |
72 | | - |
73 | | - |
74 | | -@pytest.mark.gpu2 |
75 | | -@pytest.mark.part0 |
76 | | -@pytest.mark.parametrize("tp_size, pp_size", [(1, 2), (2, 1)]) |
77 | | -def test_tinyllama_logits_processor_2gpu(tp_size: int, pp_size: int, |
78 | | - mpi_kwargs_2gpu): |
79 | | - tinyllama_logits_processor_test_harness(backend="pytorch", |
80 | | - tensor_parallel_size=tp_size, |
81 | | - pipeline_parallel_size=pp_size, |
82 | | - **mpi_kwargs_2gpu) |
83 | | - |
84 | | - |
85 | | -@pytest.mark.gpu2 |
86 | | -def test_llama_7b_lora_tp2(mpi_kwargs_2gpu): |
87 | | - llama_7b_lora_from_dir_test_harness(tensor_parallel_size=2, |
88 | | - kv_cache_config=global_kv_cache_config, |
89 | | - **mpi_kwargs_2gpu) |
90 | | - |
91 | | - |
92 | | -@pytest.mark.gpu4 |
93 | | -@skip_ray # https://nvbugs/5682551 |
94 | | -@test_lora_with_and_without_cuda_graph |
95 | | -def test_llama_7b_multi_lora_tp4(cuda_graph_config, mpi_kwargs_4gpu): |
96 | | - # For LoRA checkpoints without finetuned embedding and lm_head, we can either: |
97 | | - # (1) specify lora_target_modules, or |
98 | | - # (2) provide a lora_dir to infer the lora_target_modules. |
99 | | - lora_config = LoraConfig(lora_target_modules=['attn_q', 'attn_k', 'attn_v'], |
100 | | - max_lora_rank=8, |
101 | | - max_loras=1, |
102 | | - max_cpu_loras=8) |
103 | | - check_llama_7b_multi_lora_from_request_test_harness( |
104 | | - LLM, |
105 | | - lora_config=lora_config, |
106 | | - tensor_parallel_size=4, |
107 | | - kv_cache_config=global_kv_cache_config, |
108 | | - cuda_graph_config=cuda_graph_config, |
109 | | - **mpi_kwargs_4gpu) |
110 | | - |
111 | | - |
112 | | -@skip_ray # https://nvbugs/5727075 |
113 | | -@pytest.mark.gpu2 |
114 | | -@test_lora_with_and_without_cuda_graph |
115 | | -def test_phi3_lora_fused_modules_output_on_tp2_identical_to_tp1( |
116 | | - cuda_graph_config) -> None: |
117 | | - check_phi3_lora_fused_modules_output_tp2_identical_to_tp1( |
118 | | - LLM, cuda_graph_config=cuda_graph_config) |
119 | | - |
120 | | - |
121 | | -@skip_ray |
122 | | -@pytest.mark.gpu2 |
123 | | -def test_llm_rpc_tp2(shared_llm_2gpu): |
124 | | - _run_llm_rpc_tp2(shared_llm_2gpu) |
125 | | - |
126 | | - |
127 | | -@skip_ray |
128 | | -@pytest.mark.gpu2 |
129 | | -@pytest.mark.asyncio |
130 | | -async def test_llm_rpc_streaming_tp2(shared_llm_2gpu): |
131 | | - await _run_llm_rpc_streaming_tp2(shared_llm_2gpu) |
132 | | - |
133 | | - |
134 | 30 | def _run_llm_rpc_tp2(make_llm=LLM): |
135 | 31 | with make_llm(model=llama_model_path, |
136 | 32 | kv_cache_config=KvCacheConfig(free_gpu_memory_fraction=0.4), |
@@ -160,91 +56,178 @@ async def _run_llm_rpc_streaming_tp2(make_llm=LLM): |
160 | 56 | print(f"get result: {output}") |
161 | 57 |
|
162 | 58 |
|
163 | | -@skip_ray |
164 | | -@pytest.mark.gpu2 |
165 | | -@pytest.mark.parametrize( |
166 | | - "prompt_logprobs, logprobs, return_context_logits, return_generation_logits", |
167 | | - [ |
168 | | - (None, 1, False, |
169 | | - False), # generation logprobs only (top-1, PyTorch limit) |
170 | | - ]) |
171 | | -def test_llm_return_logprobs_streaming_tp2(prompt_logprobs, logprobs, |
172 | | - return_context_logits, |
173 | | - return_generation_logits, |
174 | | - mpi_kwargs_2gpu): |
175 | | - llm_return_logprobs_test_harness(prompt_logprobs, |
176 | | - logprobs, |
177 | | - return_context_logits, |
178 | | - return_generation_logits, |
179 | | - streaming=True, |
180 | | - backend="pytorch", |
181 | | - tp_size=2, |
182 | | - **mpi_kwargs_2gpu) |
183 | | - |
184 | | - |
185 | | -@skip_ray |
186 | | -@pytest.mark.gpu2 |
187 | | -@pytest.mark.parametrize( |
188 | | - "return_context_logits, enable_chunked_prefill, enable_iter_req_stats", |
189 | | - [ |
190 | | - (False, False, True), |
191 | | - (False, True, True), |
192 | | - ], |
193 | | -) |
194 | | -def test_llm_get_stats_pp2(return_context_logits, enable_chunked_prefill, |
195 | | - enable_iter_req_stats, mpi_kwargs_2gpu): |
196 | | - llm_get_stats_test_harness( |
197 | | - tp_size=1, |
198 | | - pp_size=2, |
199 | | - return_context_logits=return_context_logits, |
200 | | - pytorch_backend=True, |
201 | | - enable_chunked_prefill=enable_chunked_prefill, |
202 | | - enable_iter_req_stats=enable_iter_req_stats, |
203 | | - **mpi_kwargs_2gpu, |
204 | | - ) |
| 59 | +class _MultiGpuLlmTests: |
| 60 | + """Base for the multi-GPU LLM API test classes. |
205 | 61 |
|
| 62 | + Subclasses set ``n_gpus``; the class-scoped fixtures below build one shared |
| 63 | + MpiPoolSession (of that many workers) reused across the subclass's tests and |
| 64 | + torn down when the subclass finishes -- so the 2-GPU and 4-GPU pools never |
| 65 | + coexist. Fixtures are lazy, so tests that opt out (e.g. constructing a bare |
| 66 | + ``LLM``) simply don't request them and pay no session cost. |
| 67 | + """ |
| 68 | + n_gpus: int |
206 | 69 |
|
207 | | -@skip_ray |
208 | | -@pytest.mark.gpu4 |
209 | | -@pytest.mark.parametrize( |
210 | | - "return_context_logits, enable_chunked_prefill, enable_iter_req_stats", |
211 | | - [ |
212 | | - (False, False, True), |
213 | | - (False, True, True), |
214 | | - ], |
215 | | -) |
216 | | -def test_llm_get_stats_pp4(return_context_logits, enable_chunked_prefill, |
217 | | - enable_iter_req_stats, mpi_kwargs_4gpu): |
218 | | - llm_get_stats_test_harness( |
219 | | - tp_size=1, |
220 | | - pp_size=4, |
221 | | - return_context_logits=return_context_logits, |
222 | | - pytorch_backend=True, |
223 | | - enable_chunked_prefill=enable_chunked_prefill, |
224 | | - enable_iter_req_stats=enable_iter_req_stats, |
225 | | - **mpi_kwargs_4gpu, |
226 | | - ) |
| 70 | + @pytest.fixture(scope="class") |
| 71 | + def mpi_session(self): |
| 72 | + yield from _shared_mpi_session(self.n_gpus) |
227 | 73 |
|
| 74 | + @pytest.fixture(scope="class") |
| 75 | + def mpi_kwargs(self, mpi_session): |
| 76 | + return _mpi_session_kwargs(mpi_session) |
228 | 77 |
|
229 | | -@skip_ray |
230 | | -@pytest.mark.gpu2 |
231 | | -def test_llm_get_stats_tp2(mpi_kwargs_2gpu): |
232 | | - llm_get_stats_test_harness(tp_size=2, |
233 | | - pytorch_backend=True, |
234 | | - **mpi_kwargs_2gpu) |
| 78 | + @pytest.fixture(scope="class") |
| 79 | + def shared_llm(self, mpi_session): |
| 80 | + return _make_shared_llm(mpi_session) |
235 | 81 |
|
236 | 82 |
|
237 | | -@skip_ray |
238 | 83 | @pytest.mark.gpu2 |
239 | | -def test_llm_get_stats_async_tp2(mpi_kwargs_2gpu): |
240 | | - llm_get_stats_async_test_harness(tp_size=2, |
241 | | - pytorch_backend=True, |
242 | | - **mpi_kwargs_2gpu) |
| 84 | +class TestLlmMultiGpu2gpu(_MultiGpuLlmTests): |
| 85 | + """2-GPU multi-GPU LLM API tests (shared session from _MultiGpuLlmTests).""" |
| 86 | + n_gpus = 2 |
| 87 | + |
| 88 | + def test_llm_capture_request_error(self, mpi_kwargs): |
| 89 | + _test_llm_capture_request_error(pytorch_backend=True, |
| 90 | + tp_size=2, |
| 91 | + **mpi_kwargs) |
| 92 | + |
| 93 | + @pytest.mark.part0 |
| 94 | + @pytest.mark.parametrize("tp_size, pp_size", [(1, 2), (2, 1)]) |
| 95 | + def test_tinyllama_logits_processor_2gpu(self, tp_size, pp_size, |
| 96 | + mpi_kwargs): |
| 97 | + tinyllama_logits_processor_test_harness(backend="pytorch", |
| 98 | + tensor_parallel_size=tp_size, |
| 99 | + pipeline_parallel_size=pp_size, |
| 100 | + **mpi_kwargs) |
| 101 | + |
| 102 | + def test_llama_7b_lora_tp2(self, mpi_kwargs): |
| 103 | + llama_7b_lora_from_dir_test_harness( |
| 104 | + tensor_parallel_size=2, |
| 105 | + kv_cache_config=global_kv_cache_config, |
| 106 | + **mpi_kwargs) |
| 107 | + |
| 108 | + @skip_ray # https://nvbugs/5727075 |
| 109 | + @test_lora_with_and_without_cuda_graph |
| 110 | + def test_phi3_lora_fused_modules_output_on_tp2_identical_to_tp1( |
| 111 | + self, cuda_graph_config) -> None: |
| 112 | + check_phi3_lora_fused_modules_output_tp2_identical_to_tp1( |
| 113 | + LLM, cuda_graph_config=cuda_graph_config) |
| 114 | + |
| 115 | + @skip_ray |
| 116 | + def test_llm_rpc_tp2(self, shared_llm): |
| 117 | + _run_llm_rpc_tp2(shared_llm) |
| 118 | + |
| 119 | + @skip_ray |
| 120 | + @pytest.mark.asyncio |
| 121 | + async def test_llm_rpc_streaming_tp2(self, shared_llm): |
| 122 | + await _run_llm_rpc_streaming_tp2(shared_llm) |
| 123 | + |
| 124 | + @skip_ray |
| 125 | + @pytest.mark.parametrize( |
| 126 | + "prompt_logprobs, logprobs, return_context_logits, return_generation_logits", |
| 127 | + [ |
| 128 | + (None, 1, False, |
| 129 | + False), # generation logprobs only (top-1, PyTorch limit) |
| 130 | + ]) |
| 131 | + def test_llm_return_logprobs_streaming_tp2(self, prompt_logprobs, logprobs, |
| 132 | + return_context_logits, |
| 133 | + return_generation_logits, |
| 134 | + mpi_kwargs): |
| 135 | + llm_return_logprobs_test_harness(prompt_logprobs, |
| 136 | + logprobs, |
| 137 | + return_context_logits, |
| 138 | + return_generation_logits, |
| 139 | + streaming=True, |
| 140 | + backend="pytorch", |
| 141 | + tp_size=2, |
| 142 | + **mpi_kwargs) |
| 143 | + |
| 144 | + @skip_ray |
| 145 | + @pytest.mark.parametrize( |
| 146 | + "return_context_logits, enable_chunked_prefill, enable_iter_req_stats", |
| 147 | + [ |
| 148 | + (False, False, True), |
| 149 | + (False, True, True), |
| 150 | + ], |
| 151 | + ) |
| 152 | + def test_llm_get_stats_pp2(self, return_context_logits, |
| 153 | + enable_chunked_prefill, enable_iter_req_stats, |
| 154 | + mpi_kwargs): |
| 155 | + llm_get_stats_test_harness( |
| 156 | + tp_size=1, |
| 157 | + pp_size=2, |
| 158 | + return_context_logits=return_context_logits, |
| 159 | + pytorch_backend=True, |
| 160 | + enable_chunked_prefill=enable_chunked_prefill, |
| 161 | + enable_iter_req_stats=enable_iter_req_stats, |
| 162 | + **mpi_kwargs, |
| 163 | + ) |
| 164 | + |
| 165 | + @skip_ray |
| 166 | + def test_llm_get_stats_tp2(self, mpi_kwargs): |
| 167 | + llm_get_stats_test_harness(tp_size=2, |
| 168 | + pytorch_backend=True, |
| 169 | + **mpi_kwargs) |
| 170 | + |
| 171 | + @skip_ray |
| 172 | + def test_llm_get_stats_async_tp2(self, mpi_kwargs): |
| 173 | + llm_get_stats_async_test_harness(tp_size=2, |
| 174 | + pytorch_backend=True, |
| 175 | + **mpi_kwargs) |
| 176 | + |
| 177 | + @skip_ray |
| 178 | + def test_llm_get_stats_async_pp2(self, mpi_kwargs): |
| 179 | + llm_get_stats_async_test_harness(pp_size=2, |
| 180 | + pytorch_backend=True, |
| 181 | + **mpi_kwargs) |
243 | 182 |
|
244 | 183 |
|
245 | | -@skip_ray |
246 | | -@pytest.mark.gpu2 |
247 | | -def test_llm_get_stats_async_pp2(mpi_kwargs_2gpu): |
248 | | - llm_get_stats_async_test_harness(pp_size=2, |
249 | | - pytorch_backend=True, |
250 | | - **mpi_kwargs_2gpu) |
| 184 | +@pytest.mark.gpu4 |
| 185 | +class TestLlmMultiGpu4gpu(_MultiGpuLlmTests): |
| 186 | + """4-GPU multi-GPU LLM API tests (shared session from _MultiGpuLlmTests).""" |
| 187 | + n_gpus = 4 |
| 188 | + |
| 189 | + def test_tinyllama_logits_processor_tp2pp2(self, mpi_kwargs): |
| 190 | + tinyllama_logits_processor_test_harness(backend="pytorch", |
| 191 | + tensor_parallel_size=2, |
| 192 | + pipeline_parallel_size=2, |
| 193 | + **mpi_kwargs) |
| 194 | + |
| 195 | + @skip_ray # https://nvbugs/5682551 |
| 196 | + @test_lora_with_and_without_cuda_graph |
| 197 | + def test_llama_7b_multi_lora_tp4(self, cuda_graph_config, mpi_kwargs): |
| 198 | + # For LoRA checkpoints without finetuned embedding and lm_head, we can |
| 199 | + # either: (1) specify lora_target_modules, or (2) provide a lora_dir to |
| 200 | + # infer the lora_target_modules. |
| 201 | + lora_config = LoraConfig( |
| 202 | + lora_target_modules=['attn_q', 'attn_k', 'attn_v'], |
| 203 | + max_lora_rank=8, |
| 204 | + max_loras=1, |
| 205 | + max_cpu_loras=8) |
| 206 | + check_llama_7b_multi_lora_from_request_test_harness( |
| 207 | + LLM, |
| 208 | + lora_config=lora_config, |
| 209 | + tensor_parallel_size=4, |
| 210 | + kv_cache_config=global_kv_cache_config, |
| 211 | + cuda_graph_config=cuda_graph_config, |
| 212 | + **mpi_kwargs) |
| 213 | + |
| 214 | + @skip_ray |
| 215 | + @pytest.mark.parametrize( |
| 216 | + "return_context_logits, enable_chunked_prefill, enable_iter_req_stats", |
| 217 | + [ |
| 218 | + (False, False, True), |
| 219 | + (False, True, True), |
| 220 | + ], |
| 221 | + ) |
| 222 | + def test_llm_get_stats_pp4(self, return_context_logits, |
| 223 | + enable_chunked_prefill, enable_iter_req_stats, |
| 224 | + mpi_kwargs): |
| 225 | + llm_get_stats_test_harness( |
| 226 | + tp_size=1, |
| 227 | + pp_size=4, |
| 228 | + return_context_logits=return_context_logits, |
| 229 | + pytorch_backend=True, |
| 230 | + enable_chunked_prefill=enable_chunked_prefill, |
| 231 | + enable_iter_req_stats=enable_iter_req_stats, |
| 232 | + **mpi_kwargs, |
| 233 | + ) |
0 commit comments