| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | """MXFP8 MoE backend selection for the AITER FlyDSL kernel (gfx950). |
| 4 | |
| 5 | GPU-free: mocks the platform (gfx950) and the aiter fused-MoE enable flag, then |
| 6 | exercises the oracle so the FlyDSL backend is auto-picked when usable (including |
| 7 | under expert parallelism, since apply() forwards the expert_map as aiter's |
| 8 | expert_mask) and skipped (native fallback) when the device is unsupported or the |
| 9 | aiter runtime is disabled. |
| 10 | """ |
| 11 | |
| 12 | import dataclasses |
| 13 | from unittest.mock import patch |
| 14 | |
| 15 | import pytest |
| 16 | |
| 17 | from vllm.platforms import current_platform |
| 18 | |
| 19 | if not current_platform.is_rocm(): |
| 20 | pytest.skip("This test can only run on ROCm.", allow_module_level=True) |
| 21 | |
| 22 | from tests.kernels.moe.utils import make_dummy_moe_config # noqa: E402 |
| 23 | from vllm.model_executor.layers.fused_moe.activation import ( # noqa: E402 |
| 24 | MoEActivation, |
| 25 | ) |
| 26 | from vllm.model_executor.layers.fused_moe.experts.aiter_mxfp8_moe import ( # noqa: E402 |
| 27 | _AITER_SWIGLU_ALPHA, |
| 28 | _AITER_SWIGLU_BETA, |
| 29 | AiterMxfp8Experts, |
| 30 | ) |
| 31 | from vllm.model_executor.layers.fused_moe.experts.mxfp8_emulation_moe import ( # noqa: E402 |
| 32 | Mxfp8EmulationTritonExperts, |
| 33 | ) |
| 34 | from vllm.model_executor.layers.fused_moe.modular_kernel import ( # noqa: E402 |
| 35 | FusedMoEActivationFormat, |
| 36 | ) |
| 37 | from vllm.model_executor.layers.fused_moe.oracle.fp8 import ( # noqa: E402 |
| 38 | Fp8MoeBackend, |
| 39 | ) |
| 40 | from vllm.model_executor.layers.fused_moe.oracle.mxfp8 import ( # noqa: E402 |
| 41 | _BACKEND_NAME_MAP, |
| 42 | _SUPPORTED_BACKENDS, |
| 43 | _mxfp8_backend_to_kernel_cls, |
| 44 | _select_kernel_cls, |
| 45 | select_mxfp8_moe_backend, |
| 46 | ) |
| 47 | from vllm.model_executor.layers.quantization.utils.quant_utils import ( # noqa: E402 |
| 48 | kMxfp8Dynamic, |
| 49 | kMxfp8Static, |
| 50 | ) |
| 51 | |
| 52 | from vllm._aiter_ops import rocm_aiter_ops # noqa: E402 # isort: skip |
| 53 | |
| 54 | _AITER_MOD = "vllm.model_executor.layers.fused_moe.experts.aiter_mxfp8_moe" |
| 55 | |
| 56 | |
| 57 | def _config(ep_size: int = 1): |
| 58 | # AiterMxfp8Experts hardcodes SwiGLU-OAI: match its required activation and |
| 59 | # alpha/beta so is_supported_config doesn't reject the config on those grounds. |
| 60 | cfg = make_dummy_moe_config( |
| 61 | num_experts=128, |
| 62 | experts_per_token=4, |
| 63 | hidden_dim=6144, |
| 64 | activation=MoEActivation.SWIGLUOAI_UNINTERLEAVE, |
| 65 | ) |
| 66 | cfg = dataclasses.replace( |
| 67 | cfg, swiglu_alpha=_AITER_SWIGLU_ALPHA, swiglu_beta=_AITER_SWIGLU_BETA |
| 68 | ) |
| 69 | if ep_size != 1: |
| 70 | cfg = dataclasses.replace( |
| 71 | cfg, |
| 72 | moe_parallel_config=dataclasses.replace( |
| 73 | cfg.moe_parallel_config, ep_size=ep_size, use_ep=True |
| 74 | ), |
| 75 | ) |
| 76 | return cfg |
| 77 | |
| 78 | |
| 79 | def _gfx950(): |
| 80 | """Patch the platform so the device gate (gfx950 / MX) passes off-ROCm.""" |
| 81 | return patch.multiple( |
| 82 | f"{_AITER_MOD}.current_platform", |
| 83 | is_rocm=lambda: True, |
| 84 | supports_mx=lambda: True, |
| 85 | ) |
| 86 | |
| 87 | |
| 88 | def _aiter_moe_enabled(present: bool): |
| 89 | return patch.object(rocm_aiter_ops, "is_fused_moe_enabled", return_value=present) |
| 90 | |
| 91 | |
| 92 | def test_aiter_mxfp8_registered(): |
| 93 | """The FlyDSL backend is auto-selectable and reachable via --moe-backend aiter.""" |
| 94 | assert Fp8MoeBackend.AITER_MXFP8 in _SUPPORTED_BACKENDS |
| 95 | assert _BACKEND_NAME_MAP["aiter"] is Fp8MoeBackend.AITER_MXFP8 |
| 96 | assert _mxfp8_backend_to_kernel_cls(Fp8MoeBackend.AITER_MXFP8) == [ |
| 97 | AiterMxfp8Experts |
| 98 | ] |
| 99 | |
| 100 | |
| 101 | @pytest.mark.parametrize("ep_size", [1, 2]) |
| 102 | def test_ep_supported(ep_size): |
| 103 | """FlyDSL accepts both TP and EP: apply() forwards expert_map as expert_mask.""" |
| 104 | assert ( |
| 105 | AiterMxfp8Experts._supports_parallel_config( |
| 106 | _config(ep_size).moe_parallel_config |
| 107 | ) |
| 108 | is True |
| 109 | ) |
| 110 | |
| 111 | |
| 112 | @pytest.mark.parametrize( |
| 113 | "present,ep_size,supported,reason_substr", |
| 114 | [ |
| 115 | (True, 1, True, None), # gfx950 + aiter MoE + TP -> selectable |
| 116 | (True, 2, True, None), # gfx950 + aiter MoE + EP -> selectable (expert_mask) |
| 117 | ( |
| 118 | False, |
| 119 | 1, |
| 120 | False, |
| 121 | "does not support current device", |
| 122 | ), # disabled -> not selected |
| 123 | ], |
| 124 | ) |
| 125 | def test_is_supported_config(present, ep_size, supported, reason_substr): |
| 126 | with _gfx950(), _aiter_moe_enabled(present): |
| 127 | ok, reason = AiterMxfp8Experts.is_supported_config( |
| 128 | AiterMxfp8Experts, |
| 129 | _config(ep_size), |
| 130 | kMxfp8Static, |
| 131 | kMxfp8Dynamic, |
| 132 | FusedMoEActivationFormat.Standard, |
| 133 | ) |
| 134 | assert ok is supported |
| 135 | if reason_substr is not None: |
| 136 | assert reason_substr in reason |
| 137 | |
| 138 | |
| 139 | def test_explicit_moe_backend_aiter(): |
| 140 | """--moe-backend aiter: returns FlyDSL when usable (TP or EP), else a clear |
| 141 | ValueError when the aiter MoE runtime is disabled.""" |
| 142 | with _gfx950(), _aiter_moe_enabled(True): |
| 143 | assert ( |
| 144 | _select_kernel_cls(Fp8MoeBackend.AITER_MXFP8, _config(1)) |
| 145 | is AiterMxfp8Experts |
| 146 | ) |
| 147 | assert ( |
| 148 | _select_kernel_cls(Fp8MoeBackend.AITER_MXFP8, _config(2)) |
| 149 | is AiterMxfp8Experts |
| 150 | ) |
| 151 | with ( |
| 152 | _gfx950(), |
| 153 | _aiter_moe_enabled(False), |
| 154 | pytest.raises(ValueError, match="does not support current device"), |
| 155 | ): |
| 156 | _select_kernel_cls(Fp8MoeBackend.AITER_MXFP8, _config(1)) |
| 157 | |
| 158 | |
| 159 | def test_gfx950_picks_aiter(): |
| 160 | """Auto-select on real ROCm hardware with aiter MoE enabled -> FlyDSL wins.""" |
| 161 | with ( |
| 162 | patch(f"{_AITER_MOD}.current_platform.supports_mx", return_value=True), |
| 163 | _aiter_moe_enabled(True), |
| 164 | ): |
| 165 | backend, experts_cls = select_mxfp8_moe_backend(_config()) |
| 166 | assert backend is Fp8MoeBackend.AITER_MXFP8 |
| 167 | assert experts_cls is AiterMxfp8Experts |
| 168 | |
| 169 | |
| 170 | def test_gfx942_picks_emulation(): |
| 171 | """Flydsl unusable (e.g. gfx942, no FlyDSL support) -> native Triton |
| 172 | dot_scaled backend wins instead.""" |
| 173 | with patch(f"{_AITER_MOD}.current_platform.supports_mx", return_value=False): |
| 174 | backend, experts_cls = select_mxfp8_moe_backend(_config()) |
| 175 | assert backend is Fp8MoeBackend.EMULATION |
| 176 | assert experts_cls is Mxfp8EmulationTritonExperts |