@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 01baefe674
Fork 0

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 13, 20:45 UTC

Add TP parameter to attention tests (#27683)

Signed-off-by: Matthew Bonanni <mbonanni@redhat.com>

Matthew Bonanni committed Nov 3, 2025 at 16:04 UTC 01baefe674e61d156672d14b11b20055252df662
4 files changed +92 -11
.buildkite/test-pipeline.yaml
+1 -2
@@ -347,8 +347,7 @@ steps:
347 - vllm/v1/attention
348 - tests/v1/attention
349 commands:
350 - - export VLLM_DISABLE_FLASHINFER_PREFILL=1 # TODO: FI prefill is bugged and causes incorrectness, fix this
351 - - pytest -v -s v1/attention
350 + - VLLM_DISABLE_FLASHINFER_PREFILL=1 pytest -v -s v1/attention # TODO: FI prefill is bugged and causes incorrectness, fix this
351
352 - label: V1 Test others (CPU) # 5 mins
353 source_file_dependencies:
tests/v1/attention/test_attention_backends.py
+53 -5
@@ -295,6 +295,7 @@ def _test_backend_correctness(
295 block_size: int = 16,
296 atol: float = 1e-2,
297 rtol: float = 1e-2,
298 + tensor_parallel_size: int = 1,
299 ):
300 """
301 Test that all backends produce similar outputs to a reference implementation
@@ -310,13 +311,38 @@ def _test_backend_correctness(
311 4. Running each vLLM attention backend with the new queries and the
312 simulated paged KV cache.
313 5. Comparing the vLLM backend's output to the ground-truth SDPA output.
314 +
315 + Note: When tensor_parallel_size > 1, we simulate the head partitioning
316 + by overriding the model config to use fewer heads, without requiring
317 + multiple GPUs. This tests that backends work correctly with different
318 + head counts.
319 """
320 current_platform.seed_everything(42)
321 +
322 + hf_config_override = None
323 + if tensor_parallel_size > 1:
324 + from vllm.config import ModelConfig
325 +
326 + temp_config = ModelConfig(model=model, max_model_len=1)
327 + original_num_heads = temp_config.hf_text_config.num_attention_heads
328 + original_num_kv_heads = getattr(
329 + temp_config.hf_text_config, "num_key_value_heads", None
330 + )
331 + hf_config_override = {
332 + "num_attention_heads": original_num_heads // tensor_parallel_size,
333 + }
334 + if original_num_kv_heads is not None:
335 + hf_config_override["num_key_value_heads"] = max(
336 + 1, original_num_kv_heads // tensor_parallel_size
337 + )
338 +
339 vllm_config = create_vllm_config(
340 model_name=model,
341 + tensor_parallel_size=1, # Always use TP=1 to avoid multi-GPU requirements
342 max_model_len=max(batch_spec.seq_lens),
343 block_size=block_size,
344 num_gpu_blocks=8192,
345 + hf_config_override=hf_config_override,
346 )
347 device = torch.device("cuda:0")
348
@@ -503,7 +529,10 @@ def _test_backend_correctness(
529 ],
530 )
531 @pytest.mark.parametrize("model", ["meta-llama/Meta-Llama-3-8B"])
506 -def test_causal_backend_correctness(batch_spec_name: str, model: str):
532 +@pytest.mark.parametrize("tensor_parallel_size", [1, 2, 4])
533 +def test_causal_backend_correctness(
534 + batch_spec_name: str, model: str, tensor_parallel_size: int
535 +):
536 """Test backend's correctness with causal attention."""
537
538 def causal_mask_mod(
@@ -523,12 +552,23 @@ def test_causal_backend_correctness(batch_spec_name: str, model: str):
552 SMALL_BLOCK_BACKENDS = [
553 x for x in BACKENDS_TO_TEST if x not in LARGE_BLOCK_BACKENDS
554 ]
526 - _test_backend_correctness(batch_spec, model, SMALL_BLOCK_BACKENDS, causal_mask_mod)
555 + _test_backend_correctness(
556 + batch_spec,
557 + model,
558 + SMALL_BLOCK_BACKENDS,
559 + causal_mask_mod,
560 + tensor_parallel_size=tensor_parallel_size,
561 + )
562
563 # Fast FlexAttention needs to run with block_size=128
564 if LARGE_BLOCK_BACKENDS:
565 _test_backend_correctness(
531 - batch_spec, model, LARGE_BLOCK_BACKENDS, causal_mask_mod, block_size=128
566 + batch_spec,
567 + model,
568 + LARGE_BLOCK_BACKENDS,
569 + causal_mask_mod,
570 + block_size=128,
571 + tensor_parallel_size=tensor_parallel_size,
572 )
573
574
@@ -545,7 +585,10 @@ SLIDING_WINDOW_BACKENDS_TO_TEST = [
585 ["small_decode", "small_prefill", "mixed_medium", "large_decode", "large_prefill"],
586 )
587 @pytest.mark.parametrize("model", ["microsoft/Phi-tiny-MoE-instruct"])
548 -def test_sliding_window_backend_correctness(batch_spec_name: str, model: str):
588 +@pytest.mark.parametrize("tensor_parallel_size", [1, 2, 4])
589 +def test_sliding_window_backend_correctness(
590 + batch_spec_name: str, model: str, tensor_parallel_size: int
591 +):
592 """Test backend's correctness with sliding window attention."""
593
594 def sliding_window_mask_mod(
@@ -575,7 +618,11 @@ def test_sliding_window_backend_correctness(batch_spec_name: str, model: str):
618 x for x in SLIDING_WINDOW_BACKENDS_TO_TEST if x not in LARGE_BLOCK_BACKENDS
619 ]
620 _test_backend_correctness(
578 - batch_spec, model, SMALL_BLOCK_BACKENDS, sliding_window_mask_mod_fn
621 + batch_spec,
622 + model,
623 + SMALL_BLOCK_BACKENDS,
624 + sliding_window_mask_mod_fn,
625 + tensor_parallel_size=tensor_parallel_size,
626 )
627
628 # Fast FlexAttention needs to run with block_size=128
@@ -586,4 +633,5 @@ def test_sliding_window_backend_correctness(batch_spec_name: str, model: str):
633 LARGE_BLOCK_BACKENDS,
634 sliding_window_mask_mod_fn,
635 block_size=128,
636 + tensor_parallel_size=tensor_parallel_size,
637 )
tests/v1/attention/test_mla_backends.py
+29 -2
@@ -394,8 +394,11 @@ def run_attention_backend(
394 "spec_decode_medium",
395 ],
396 )
397 -@pytest.mark.parametrize("model", ["deepseek-ai/DeepSeek-V2-Lite-Chat"])
398 -def test_backend_correctness(dist_init, batch_spec_name: str, model: str):
397 +@pytest.mark.parametrize("model", ["deepseek-ai/DeepSeek-R1"])
398 +@pytest.mark.parametrize("tensor_parallel_size", [1, 4, 8, 16])
399 +def test_backend_correctness(
400 + dist_init, batch_spec_name: str, model: str, tensor_parallel_size: int
401 +):
402 """
403 Test that all backends produce similar outputs to a reference implementation
404 using torch.nn.functional.scaled_dot_product_attention.
@@ -410,6 +413,11 @@ def test_backend_correctness(dist_init, batch_spec_name: str, model: str):
413 4. Running each vLLM attention backend with the new queries and the
414 simulated paged KV cache.
415 5. Comparing the vLLM backend's output to the ground-truth SDPA output.
416 +
417 + Note: When tensor_parallel_size > 1, we simulate the head partitioning
418 + by overriding the model config to use fewer heads, without requiring
419 + multiple GPUs. This tests that backends work correctly with different
420 + head counts.
421 """
422
423 batch_spec = BATCH_SPECS[batch_spec_name]
@@ -423,11 +431,30 @@ def test_backend_correctness(dist_init, batch_spec_name: str, model: str):
431 # Add 1 for null block at index 0, and some buffer
432 num_gpu_blocks = required_blocks + 1 + 100
433
434 + hf_config_override = None
435 + if tensor_parallel_size > 1:
436 + from vllm.config import ModelConfig
437 +
438 + temp_config = ModelConfig(model=model, max_model_len=1)
439 + original_num_heads = temp_config.hf_text_config.num_attention_heads
440 + original_num_kv_heads = getattr(
441 + temp_config.hf_text_config, "num_key_value_heads", None
442 + )
443 + hf_config_override = {
444 + "num_attention_heads": original_num_heads // tensor_parallel_size,
445 + }
446 + if original_num_kv_heads is not None:
447 + hf_config_override["num_key_value_heads"] = max(
448 + 1, original_num_kv_heads // tensor_parallel_size
449 + )
450 +
451 vllm_config = create_vllm_config(
452 model_name=model,
453 + tensor_parallel_size=1, # Always use TP=1 to avoid multi-GPU requirements
454 max_model_len=max(batch_spec.seq_lens),
455 num_gpu_blocks=num_gpu_blocks,
456 block_size=default_block_size,
457 + hf_config_override=hf_config_override,
458 )
459
460 # For spec decode tests, add a speculative_config to set the reorder_batch_threshold
tests/v1/attention/test_sparse_mla_backends.py
+9 -2
@@ -113,7 +113,10 @@ def _quantize_dequantize_fp8_ds_mla(
113
114 @pytest.mark.parametrize("batch_name", list(SPARSE_BACKEND_BATCH_SPECS.keys()))
115 @pytest.mark.parametrize("kv_cache_dtype", ["fp8_ds_mla", "auto"])
116 -def test_sparse_backend_decode_correctness(dist_init, batch_name, kv_cache_dtype):
116 +@pytest.mark.parametrize("tensor_parallel_size", [1, 2, 4])
117 +def test_sparse_backend_decode_correctness(
118 + dist_init, batch_name, kv_cache_dtype, tensor_parallel_size
119 +):
120 if not torch.cuda.is_available():
121 pytest.skip("CUDA is required for sparse MLA decode test")
122
@@ -135,8 +138,11 @@ def test_sparse_backend_decode_correctness(dist_init, batch_name, kv_cache_dtype
138 total_cache_tokens = sum(batch_spec.seq_lens)
139 block_size = 64
140
141 + # Note: We use TP=1 to avoid multi-GPU requirements in CI.
142 + # The test simulates head partitioning via mocked methods below.
143 vllm_config = create_vllm_config(
144 model_name="deepseek-ai/DeepSeek-V2-Lite-Chat",
145 + tensor_parallel_size=1,
146 max_model_len=max_seqlen,
147 num_gpu_blocks=max(2048, cdiv(total_cache_tokens, block_size) + 1),
148 block_size=block_size,
@@ -156,7 +162,8 @@ def test_sparse_backend_decode_correctness(dist_init, batch_name, kv_cache_dtype
162 )
163 model_config.dtype = dtype
164 model_config.get_num_attention_heads = MethodType(
159 - lambda self, parallel_config: num_heads, model_config
165 + lambda self, parallel_config: max(1, num_heads // tensor_parallel_size),
166 + model_config,
167 )
168 model_config.get_num_kv_heads = MethodType(
169 lambda self, parallel_config: 1, model_config