[ROCm][CI] skip the ROCm MRV1 default where MRV1 cannot serve the config (#58535)

Signed-off-by: Stefan Koncarevic <Stefan.Koncarevic@amd.com> Co-authored-by: Andreas Karatzas <akaratza@amd.com>

stefankoncarevic committed Sep 24, 2026 at 22:36 UTC e33de821c0df5c15d0fad990a754f3b69a6478e3
5 files changed +91 -2
.buildkite/test_areas/lm_eval.yaml
+1
@@ -307,6 +307,7 @@ steps:
307 - csrc/
308 - tests/evals/gsm8k/configs/Kimi-K3-pruned75-DSpark-AITER-TP4.yaml
309 - tests/evals/gsm8k/configs/DeepSeek-V4-Flash-DSpark-AITER-TEP4.yaml
310 + - tests/evals/gsm8k/configs/DeepSeek-V4-Flash-DSpark-FP8-TP4-ROCm.yaml
311 - tests/evals/gsm8k/configs/models-spec-decode-rocm.txt
312 - tests/evals/gsm8k/test_gsm8k_correctness.py
313 - tests/evals/gsm8k/gsm8k_eval.py
tests/evals/gsm8k/configs/DeepSeek-V4-Flash-DSpark-FP8-TP4-ROCm.yaml new
+28
@@ -0,0 +1,28 @@
1 +model_name: "deepseek-ai/DeepSeek-V4-Flash-DSpark"
2 +accuracy_threshold: 0.92
3 +tolerance: 0.08
4 +min_acceptance_length: 1.2
5 +num_questions: 1319
6 +num_fewshot: 5
7 +startup_max_wait_seconds: 1800
8 +env:
9 + VLLM_ROCM_USE_AITER: "1"
10 +server_args: >-
11 + --tokenizer-mode deepseek_v4
12 + --trust-remote-code
13 + --max-model-len 8192
14 + --tensor-parallel-size 4
15 + --enable-expert-parallel
16 + --all2all-backend allgather_reducescatter
17 + --block-size 256
18 + --gpu-memory-utilization 0.5
19 + --kv-cache-dtype fp8
20 + --attention_config.indexer_kv_dtype=fp8
21 + --max-num-batched-tokens 16384
22 + --max-num-seqs 128
23 + --enforce-eager
24 + --speculative-config '{"method":"dspark",
25 + "model":"deepseek-ai/DeepSeek-V4-Flash-DSpark",
26 + "num_speculative_tokens":7,
27 + "draft_sample_method":"probabilistic",
28 + "enable_adaptive_verification":false}'
tests/evals/gsm8k/configs/models-spec-decode-rocm.txt
+1
@@ -1,2 +1,3 @@
1 Kimi-K3-pruned75-DSpark-AITER-TP4.yaml
2 DeepSeek-V4-Flash-DSpark-AITER-TEP4.yaml
3 +DeepSeek-V4-Flash-DSpark-FP8-TP4-ROCm.yaml
tests/test_config.py
+47
@@ -550,11 +550,58 @@ def test_rocm_keeps_compiled_deepseek_defaults(monkeypatch):
550 model_config=SimpleNamespace(architectures=["DeepseekV32ForCausalLM"]),
551 attention_config=AttentionConfig(),
552 )
553 + config._get_v1_model_runner_unsupported_features = lambda: []
554 assert VllmConfig.use_v2_model_runner.fget(config) is False
555 finally:
556 default_breakable_cudagraph_architectures.cache_clear()
557
558
559 +def test_rocm_mrv1_default_yields_to_v1_unsupported_config(monkeypatch):
560 + """The ROCm V1 default is a speed preference, not a capability claim.
561 +
562 + DSpark runs only on V2, so pinning DeepSeek V4 to V1 would fail config
563 + validation instead of serving it. With nothing V1 refuses, it still holds.
564 + """
565 + from vllm.platforms import current_platform
566 +
567 + monkeypatch.setattr(current_platform, "is_rocm", lambda: True)
568 + monkeypatch.setattr(vllm_config_module, "HAS_TRITON", True)
569 + monkeypatch.delenv("VLLM_USE_V2_MODEL_RUNNER", raising=False)
570 +
571 + config = SimpleNamespace(
572 + model_config=SimpleNamespace(
573 + architectures=["DeepseekV4ForCausalLM"], is_diffusion=False
574 + ),
575 + attention_config=AttentionConfig(),
576 + parallel_config=SimpleNamespace(
577 + prefill_context_parallel_size=1,
578 + pipeline_parallel_size=1,
579 + enable_batch_sharded_sampling=False,
580 + ),
581 + scheduler_config=SimpleNamespace(async_scheduling=False),
582 + speculative_config=None,
583 + )
584 + config._dflash_needs_multi_kv_group = lambda: False
585 + config._is_dflash2_draft = lambda: False
586 + config._get_v2_model_runner_unsupported_features = lambda: []
587 + # The real predicate, so the test also pins where dspark lands in it.
588 + config._get_v1_model_runner_unsupported_features = lambda: (
589 + VllmConfig._get_v1_model_runner_unsupported_features(config)
590 + )
591 +
592 + assert VllmConfig.use_v2_model_runner.fget(config) is False
593 +
594 + config.speculative_config = SimpleNamespace(
595 + method="dspark", enable_adaptive_verification=False
596 + )
597 + assert VllmConfig.use_v2_model_runner.fget(config) is True
598 +
599 + # Yielding is not the same as selecting V2: the later checks still run, so
600 + # a config neither runner can serve lands on V1 and fails validation there.
601 + config._get_v2_model_runner_unsupported_features = lambda: ["sequence parallelism"]
602 + assert VllmConfig.use_v2_model_runner.fget(config) is False
603 +
604 +
605 @pytest.mark.parametrize(
606 ("model", "architecture"),
607 [
vllm/config/vllm.py
+14 -2
@@ -722,11 +722,23 @@ class VllmConfig:
722 if model_config is not None and current_platform.is_rocm():
723 architectures = getattr(model_config, "architectures", ())
724 if any(arch in ROCM_DEFAULT_MRV1_ARCHITECTURES for arch in architectures):
725 + # This default is a speed preference, not a claim that V1 can
726 + # serve the config, so it yields where V1 cannot. It yields by
727 + # falling through to the checks below, not by selecting V2.
728 + v1_unsupported = self._get_v1_model_runner_unsupported_features()
729 + if not v1_unsupported:
730 + logger.warning_once(
731 + "Defaulting to V1 model runner on ROCm for model "
732 + "architectures: %s",
733 + ", ".join(architectures),
734 + )
735 + return False
736 logger.warning_once(
726 - "Defaulting to V1 model runner on ROCm for model architectures: %s",
737 + "Skipping the ROCm V1 model runner default for %s: V1 does "
738 + "not support %s.",
739 ", ".join(architectures),
740 + ", ".join(v1_unsupported),
741 )
729 - return False
742
743 if not HAS_TRITON:
744 logger.warning_once(