Files
vllm-omni/tests/diffusion/attention/test_ring_backend_selection.py
T
95a9311696 [CI] Select mirror_hardwares presets via MIRROR_HW (H100/B200) (#5543)
Signed-off-by: wangyu <410167048@qq.com>
Signed-off-by: lishunyang12 <lishunyang12@163.com>
Signed-off-by: [Your Name] <your.email@example.com>
Signed-off-by: wangyu <53896905+yenuo26@users.noreply.github.com>
Signed-off-by: Bo Li <22713281+bobboli@users.noreply.github.com>
Co-authored-by: lishunyang12 <lishunyang12@163.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Bo Li <22713281+bobboli@users.noreply.github.com>
2026-09-02 15:39:49 +00:00

200 lines
7.6 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
import importlib
import sys
from types import SimpleNamespace
import pytest
import torch
from vllm_omni.diffusion.attention.backends.ring import ring_globals, ring_kernels
from vllm_omni.diffusion.attention.parallel import factory, ring
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
def test_source_build_fa3_is_hopper_only(monkeypatch):
fake_interface = SimpleNamespace(
_flash_attn_forward=lambda *args, **kwargs: None,
flash_attn_func=lambda *args, **kwargs: None,
)
try:
with monkeypatch.context() as context:
context.setitem(sys.modules, "flash_attn_interface", fake_interface)
reloaded = importlib.reload(ring_globals)
assert reloaded.HAS_FA3
assert reloaded.FA3_SUPPORTED_CUDA_MAJORS == frozenset({9})
finally:
importlib.reload(ring_globals)
@pytest.mark.parametrize(
("capability", "expected"),
[
((8, 0), True),
((8, 9), True),
((9, 0), True),
((10, 0), False),
((10, 3), False),
((12, 0), False),
],
)
def test_can_use_fa3_checks_device_arch(monkeypatch, capability, expected):
monkeypatch.setattr(ring, "HAS_FA3", True)
monkeypatch.setattr(ring, "FA3_SUPPORTED_CUDA_MAJORS", frozenset({8, 9}))
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda _device: capability)
assert ring._can_use_fa3(torch.device("cuda")) is expected
def test_can_use_fa3_preserves_unknown_extension_contract(monkeypatch):
monkeypatch.setattr(ring, "HAS_FA3", True)
monkeypatch.setattr(ring, "FA3_SUPPORTED_CUDA_MAJORS", None)
assert ring._can_use_fa3(torch.device("cuda"))
@pytest.mark.parametrize(
("capability", "expected"),
[
((8, 0), True),
((9, 0), True),
((10, 0), False),
((10, 3), False),
((12, 0), False),
],
)
def test_can_use_fa2_checks_device_arch(monkeypatch, capability, expected):
monkeypatch.setattr(ring, "HAS_FLASH_ATTN", True)
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda _device: capability)
assert ring._can_use_fa2(torch.device("cuda")) is expected
def test_ring_falls_back_to_sdpa_when_fa3_extension_has_no_device_kernel(monkeypatch):
monkeypatch.setattr(ring, "HAS_FA3", True)
monkeypatch.setattr(ring, "HAS_FA4", False)
monkeypatch.setattr(ring, "HAS_FLASH_ATTN", False)
monkeypatch.setattr(ring, "HAS_AITER", False)
monkeypatch.setattr(ring, "_can_use_fa3", lambda _device: False)
expected = torch.randn(1, 2, 1, 8)
def fake_ring_sdpa(*args, **kwargs):
return expected
module_name = "vllm_omni.diffusion.attention.backends.ring_pytorch_attn"
monkeypatch.setitem(sys.modules, module_name, SimpleNamespace(ring_pytorch_attn_func=fake_ring_sdpa))
strategy = ring.RingParallelAttention(SimpleNamespace(ring_group=object()))
query = torch.randn(1, 2, 1, 8, dtype=torch.bfloat16)
actual = strategy.run_attention(query, query, query, attn_metadata=None)
assert actual is expected
def test_explicit_ring_backend_does_not_fallback_to_sdpa(monkeypatch):
monkeypatch.setattr(ring, "HAS_FA3", True)
monkeypatch.setattr(ring, "HAS_FA4", False)
monkeypatch.setattr(ring, "HAS_FLASH_ATTN", False)
monkeypatch.setattr(ring, "HAS_AITER", False)
monkeypatch.setattr(ring, "_can_use_fa3", lambda _device: False)
strategy = ring.RingParallelAttention(
SimpleNamespace(ring_group=object()),
attn_backend_pref="FLASH_ATTN",
attn_backend_explicit=True,
)
query = torch.randn(1, 2, 1, 8, dtype=torch.bfloat16)
with pytest.raises(RuntimeError, match="explicitly selected"):
strategy.run_attention(query, query, query, attn_metadata=None)
@pytest.mark.parametrize(
"backend_pref",
[
"CUDNN_ATTN",
"FLASH_ATTN_HUB",
"FLASH_ATTN_3_HUB",
],
)
def test_explicit_non_ring_backend_is_rejected(monkeypatch, backend_pref):
# Local FA is available so a missing rejection would silently run FA4/FA3/FA2
# instead of the requested Hub/cuDNN backend.
monkeypatch.setattr(ring, "HAS_FA4", True)
monkeypatch.setattr(ring, "_can_use_fa4", lambda _device: True)
module_name = "vllm_omni.diffusion.attention.backends.ring_pytorch_attn"
monkeypatch.setitem(
sys.modules,
module_name,
SimpleNamespace(ring_pytorch_attn_func=lambda *args, **kwargs: pytest.fail("unexpected SDPA fallback")),
)
monkeypatch.setitem(
sys.modules,
"vllm_omni.diffusion.attention.backends.ring_flash_attn",
SimpleNamespace(ring_flash_attn_func=lambda *args, **kwargs: pytest.fail("unexpected local FA ring")),
)
strategy = ring.RingParallelAttention(
SimpleNamespace(ring_group=object()),
attn_backend_pref=backend_pref,
attn_backend_explicit=True,
)
query = torch.randn(1, 2, 1, 8, dtype=torch.bfloat16)
with pytest.raises(ValueError, match="ring sequence parallelism has no implementation"):
strategy.run_attention(query, query, query, attn_metadata=None)
def test_explicit_flash_ring_rejects_float32_instead_of_falling_back(monkeypatch):
module_name = "vllm_omni.diffusion.attention.backends.ring_pytorch_attn"
monkeypatch.setitem(
sys.modules,
module_name,
SimpleNamespace(ring_pytorch_attn_func=lambda *args, **kwargs: pytest.fail("unexpected SDPA fallback")),
)
strategy = ring.RingParallelAttention(
SimpleNamespace(ring_group=object()),
attn_backend_pref="FLASH_ATTN",
attn_backend_explicit=True,
)
query = torch.randn(1, 2, 1, 8, dtype=torch.float32)
with pytest.raises(ValueError, match="does not support float32"):
strategy.run_attention(query, query, query, attn_metadata=None)
def test_pytorch_ring_flash_op_rejects_float32():
query = torch.randn(1, 2, 1, 8, dtype=torch.float32)
with pytest.raises(ValueError, match="does not support float32"):
ring_kernels.pytorch_attn_forward(query, query, query, op_type="flash")
def test_configured_sp_does_not_fallback_when_group_is_unavailable(monkeypatch):
parallel_config = SimpleNamespace(ulysses_degree=2, ring_degree=1, allgather_degree=1)
forward_context = SimpleNamespace(omni_diffusion_config=SimpleNamespace(parallel_config=parallel_config))
monkeypatch.setattr(factory, "is_forward_context_available", lambda: True)
monkeypatch.setattr(factory, "get_forward_context", lambda: forward_context)
monkeypatch.setattr(
factory,
"get_sp_group",
lambda: (_ for _ in ()).throw(RuntimeError("SP group is not initialized")),
)
with pytest.raises(RuntimeError, match="SP is configured"):
factory.build_parallel_attention_strategy(scatter_idx=2, gather_idx=1, use_sync=False)
def test_configured_sp_rejects_single_rank_group(monkeypatch):
parallel_config = SimpleNamespace(ulysses_degree=2, ring_degree=1, allgather_degree=1)
forward_context = SimpleNamespace(omni_diffusion_config=SimpleNamespace(parallel_config=parallel_config))
monkeypatch.setattr(factory, "is_forward_context_available", lambda: True)
monkeypatch.setattr(factory, "get_forward_context", lambda: forward_context)
monkeypatch.setattr(factory, "get_sp_group", lambda: SimpleNamespace())
monkeypatch.setattr(factory, "get_sequence_parallel_world_size", lambda: 1)
with pytest.raises(RuntimeError, match="world size is not greater than one"):
factory.build_parallel_attention_strategy(scatter_idx=2, gather_idx=1, use_sync=False)