[ROCm][Kimi-K3] Make VLLM_ROCM_USE_AITER_MOE_SITUV2 select a4w4/a8w4/a16w4 (#58201)
Signed-off-by: Hongxia Yang <hongxia.yang@amd.com>
Hongxia Yang committed
Sep 26, 2026 at 22:26 UTC
3137ff07739f0cd19e06119506c6432a4a7e77ad
5 files changed
+103
-88
tests/kernels/moe/test_rocm_aiter_moe.py
+38
-46
@@ -566,72 +566,64 @@ def test_aiter_moe_shared_experts_enablement_follows_env(
566
assert rocm_aiter_ops.is_fusion_moe_shared_experts_enabled() is expected
567
568
569
-def test_aiter_moe_situv2_syncs_aiter_a4w4_env(
569
+@pytest.mark.parametrize(
570
+ "value,expected_act,expected_env",
571
+ [
572
+ # Unset / auto / legacy "1" all mean the a4w4 default.
573
+ (None, "a4w4", {"AITER_SITUV2_A4W4": "1"}),
574
+ ("auto", "a4w4", {"AITER_SITUV2_A4W4": "1"}),
575
+ ("1", "a4w4", {"AITER_SITUV2_A4W4": "1"}),
576
+ ("a4w4", "a4w4", {"AITER_SITUV2_A4W4": "1"}),
577
+ ("0", "a16w4", {}),
578
+ ("a16w4", "a16w4", {}),
579
+ ("A8W4", "a8w4", {"AITER_SITUV2_A8W4": "1"}),
580
+ ],
581
+)
582
+def test_aiter_moe_situv2_activation_syncs_aiter_env(
583
+ value: str | None,
584
+ expected_act: str,
585
+ expected_env: dict[str, str],
586
monkeypatch: pytest.MonkeyPatch,
587
):
572
- """SiTUv2 MoE should route to AITER a4w4 and clear legacy a8w4 overrides."""
573
- from vllm._aiter_ops import rocm_aiter_ops
574
-
575
- _assert_aiter_supported()
576
-
577
- with monkeypatch.context() as mp:
578
- mp.delenv("AITER_SITUV2_A8W4", raising=False)
579
- mp.delenv("AITER_SITUV2_A4W4", raising=False)
580
- mp.setenv("VLLM_ROCM_USE_AITER", "1")
581
- mp.setenv("VLLM_ROCM_USE_AITER_MOE", "1")
582
- mp.setenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", "1")
583
- _reload_envs()
584
- rocm_aiter_ops.refresh_env_variables()
585
-
586
- import os
587
-
588
- assert os.environ.get("AITER_SITUV2_A4W4") == "1"
589
- assert "AITER_SITUV2_A8W4" not in os.environ
590
-
588
+ """Each SiTUv2 activation choice sets exactly its AITER dispatch env."""
589
+ import os
590
592
-def test_aiter_moe_situv2_legacy_a8w4_alias_enables_a4w4(
593
- monkeypatch: pytest.MonkeyPatch,
594
-):
595
- """Deprecated VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4 still enables SiTUv2 a4w4."""
591
from vllm._aiter_ops import rocm_aiter_ops
592
593
_assert_aiter_supported()
594
595
with monkeypatch.context() as mp:
601
- mp.delenv("AITER_SITUV2_A8W4", raising=False)
602
- mp.delenv("AITER_SITUV2_A4W4", raising=False)
603
- mp.delenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", raising=False)
596
+ # Stale AITER overrides must be replaced by the vLLM selection.
597
+ mp.setenv("AITER_SITUV2_A8W4", "1")
598
+ mp.setenv("AITER_SITUV2_A4W4", "1")
599
mp.setenv("VLLM_ROCM_USE_AITER", "1")
600
mp.setenv("VLLM_ROCM_USE_AITER_MOE", "1")
606
- mp.setenv("VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4", "1")
601
+ if value is None:
602
+ mp.delenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", raising=False)
603
+ else:
604
+ mp.setenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", value)
605
_reload_envs()
606
rocm_aiter_ops.refresh_env_variables()
607
610
- import os
611
-
612
- assert os.environ.get("AITER_SITUV2_A4W4") == "1"
613
- assert "AITER_SITUV2_A8W4" not in os.environ
608
+ assert rocm_aiter_ops.get_fused_moe_situv2_activation() == expected_act
609
+ assert rocm_aiter_ops.is_fused_moe_situv2_gate_up_interleaved() is (
610
+ expected_act == "a8w4"
611
+ )
612
+ assert rocm_aiter_ops.is_fused_moe_situv2_enabled() is (expected_act != "a16w4")
613
+ for name in ("AITER_SITUV2_A8W4", "AITER_SITUV2_A4W4"):
614
+ assert os.environ.get(name) == expected_env.get(name)
615
616
616
-def test_aiter_moe_situv2_clears_aiter_env_when_disabled(
617
+def test_aiter_moe_situv2_rejects_unknown_activation(
618
monkeypatch: pytest.MonkeyPatch,
619
):
619
- from vllm._aiter_ops import rocm_aiter_ops
620
-
621
- _assert_aiter_supported()
622
-
620
with monkeypatch.context() as mp:
624
- mp.setenv("AITER_SITUV2_A4W4", "1")
625
- mp.setenv("VLLM_ROCM_USE_AITER", "1")
626
- mp.setenv("VLLM_ROCM_USE_AITER_MOE", "1")
627
- mp.delenv("VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4", raising=False)
628
- mp.setenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", "0")
621
+ mp.setenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", "a8w8")
622
_reload_envs()
630
- rocm_aiter_ops.refresh_env_variables()
631
-
632
- import os
623
+ import vllm.envs as envs
624
634
- assert "AITER_SITUV2_A4W4" not in os.environ
625
+ with pytest.raises(ValueError, match="VLLM_ROCM_USE_AITER_MOE_SITUV2"):
626
+ _ = envs.VLLM_ROCM_USE_AITER_MOE_SITUV2
627
628
629
@pytest.mark.parametrize("moe_padding", [True, False])
vllm/_aiter_ops.py
+51
-23
@@ -1870,28 +1870,39 @@ def _mhc_delayed_pre_tail(
1870
_OPS_REGISTERED = False
1871
1872
1873
-def _sync_aiter_situv2_moe_env() -> None:
1874
- """Mirror the SiTUv2 MoE toggle into AITER's a4w4 dispatch env.
1873
+_AITER_SITUV2_ACT_ENV = {
1874
+ "a8w4": "AITER_SITUV2_A8W4",
1875
+ "a4w4": "AITER_SITUV2_A4W4",
1876
+}
1877
+
1878
1876
- AITER selects afp8 vs afp4 activation kernels via AITER_SITUV2_A8W4 /
1877
- AITER_SITUV2_A4W4 (see ROCm/aiter fused_moe.py, A8W4 checked first).
1878
- When VLLM_ROCM_USE_AITER_MOE_SITUV2 is enabled we route to a4w4
1879
- (afp4_wfp4_fp4 kernels) and clear any legacy AITER_SITUV2_A8W4 override.
1879
+def _resolve_situv2_activation() -> str:
1880
+ """VLLM_ROCM_USE_AITER_MOE_SITUV2 -> a4w4 | a8w4 | a16w4.
1881
1881
- Requires AITER with ROCm/aiter#4463 (first tagged in v0.1.20): a4w4
1882
- dispatch plus kimik3_a4w4_{un,}tuned_fmoe.csv. Older AITER still runs
1883
- afp4 FlyDSL but falls back to heuristic configs, which is not the
1884
- tuned a4w4 path this recipe is meant to use.
1882
+ auto (default) and the legacy 1 mean a4w4; legacy 0 means a16w4.
1883
"""
1886
- import os
1884
+ value = envs.VLLM_ROCM_USE_AITER_MOE_SITUV2.lower()
1885
+ if value in ("auto", "1"):
1886
+ return "a4w4"
1887
+ if value == "0":
1888
+ return "a16w4"
1889
+ return value
1890
1888
- import vllm.envs as envs
1891
1890
- if envs.VLLM_ROCM_USE_AITER_MOE_SITUV2:
1891
- os.environ["AITER_SITUV2_A4W4"] = "1"
1892
- os.environ.pop("AITER_SITUV2_A8W4", None)
1893
- else:
1894
- os.environ.pop("AITER_SITUV2_A4W4", None)
1892
+def _sync_aiter_situv2_moe_env() -> None:
1893
+ """Set the AITER_SITUV2_* env matching VLLM_ROCM_USE_AITER_MOE_SITUV2.
1894
+
1895
+ AITER reads AITER_SITUV2_A8W4 / AITER_SITUV2_A4W4 and defaults to a16w4,
1896
+ so exactly one is set for a8w4/a4w4 and both are cleared for a16w4.
1897
+ """
1898
+ import os
1899
+
1900
+ selected = _AITER_SITUV2_ACT_ENV.get(_resolve_situv2_activation())
1901
+ for name in _AITER_SITUV2_ACT_ENV.values():
1902
+ if name == selected:
1903
+ os.environ[name] = "1"
1904
+ else:
1905
+ os.environ.pop(name, None)
1906
1907
1908
class rocm_aiter_ops:
@@ -1917,7 +1928,8 @@ class rocm_aiter_ops:
1928
VLLM_ROCM_USE_AITER_FP4_ASM_GEMM: Controls FP4 assembly GEMM.
1929
VLLM_ROCM_USE_AITER_TRITON_ROPE: Controls Triton rotary embeddings.
1930
VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS: Controls shared expert fusion.
1920
- VLLM_ROCM_USE_AITER_MOE_SITUV2: Controls SiTUv2 FlyDSL MoE (a4w4).
1931
+ VLLM_ROCM_USE_AITER_MOE_SITUV2: SiTUv2 FlyDSL MoE activation
1932
+ dtype (a16w4 | a8w4 | a4w4).
1933
VLLM_ROCM_USE_AITER_TRITON_GEMM: Controls Triton unquantized GEMM.
1934
1935
Note:
@@ -1987,7 +1999,7 @@ class rocm_aiter_ops:
1999
# TODO: Consolidate under VLLM_ROCM_USE_AITER_ROPE
2000
_TRITON_ROTARY_EMBED = envs.VLLM_ROCM_USE_AITER_TRITON_ROPE
2001
_MOE_SHARED_EXPERTS_ENABLED = envs.VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS
1990
- _MOE_SITUV2 = envs.VLLM_ROCM_USE_AITER_MOE_SITUV2
2002
+ _MOE_SITUV2 = _resolve_situv2_activation()
2003
# TODO: Consolidate under _LINEAR_ENABLED
2004
_TRITON_UNQUANT_GEMM = envs.VLLM_ROCM_USE_AITER_TRITON_GEMM
2005
# Lazily probed: whether aiter.topk_softmax supports the
@@ -2016,7 +2028,7 @@ class rocm_aiter_ops:
2028
cls._FP4_GEMM_DYNAMIC_QUANT_ASM = envs.VLLM_ROCM_USE_AITER_FP4_ASM_GEMM
2029
cls._TRITON_ROTARY_EMBED = envs.VLLM_ROCM_USE_AITER_TRITON_ROPE
2030
cls._MOE_SHARED_EXPERTS_ENABLED = envs.VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS
2019
- cls._MOE_SITUV2 = envs.VLLM_ROCM_USE_AITER_MOE_SITUV2
2031
+ cls._MOE_SITUV2 = _resolve_situv2_activation()
2032
_sync_aiter_situv2_moe_env()
2033
cls._TRITON_UNQUANT_GEMM = envs.VLLM_ROCM_USE_AITER_TRITON_GEMM
2034
cls._MOE_DISPATCH_POLICY = envs.VLLM_ROCM_AITER_MOE_DISPATCH_POLICY
@@ -2132,9 +2144,25 @@ class rocm_aiter_ops:
2144
@classmethod
2145
@if_aiter_supported
2146
def is_fused_moe_situv2_enabled(cls) -> bool:
2135
- # _MOE_SITUV2 is a variant of aiter fused moe, so aiter
2136
- # fused moe must be enabled as well.
2137
- return cls.is_fused_moe_enabled() and cls._MOE_SITUV2
2147
+ """True when a low-precision (a8w4/a4w4) SiTUv2 activation is selected."""
2148
+ return cls.is_fused_moe_enabled() and cls._MOE_SITUV2 != "a16w4"
2149
+
2150
+ @classmethod
2151
+ @if_aiter_supported
2152
+ def get_fused_moe_situv2_activation(cls) -> str:
2153
+ """SiTUv2 activation dtype name: a16w4, a8w4 or a4w4."""
2154
+ return cls._MOE_SITUV2
2155
+
2156
+ @classmethod
2157
+ @if_aiter_supported
2158
+ def is_fused_moe_situv2_gate_up_interleaved(cls) -> bool:
2159
+ """Whether the SiTUv2 kernels expect gate/up-interleaved w13.
2160
+
2161
+ The a8w4 FlyDSL stage-1 kernels (_gui_) are interleaved; a16w4 and
2162
+ a4w4 are separated. Weight shuffle (oracle/mxfp4.py) and gate_mode
2163
+ (experts/rocm_aiter_moe.py) must both use this.
2164
+ """
2165
+ return cls._MOE_SITUV2 == "a8w4"
2166
2167
@classmethod
2168
@if_aiter_supported
vllm/envs.py
+8
-13
@@ -141,7 +141,7 @@ if TYPE_CHECKING:
141
VLLM_ROCM_USE_AITER_LINEAR_HIPBMM: bool = False
142
VLLM_ROCM_USE_AITER_MOE: bool = True
143
VLLM_ROCM_AITER_MOE_DISPATCH_POLICY: int = 0
144
- VLLM_ROCM_USE_AITER_MOE_SITUV2: bool = False
144
+ VLLM_ROCM_USE_AITER_MOE_SITUV2: Literal["auto", "a4w4", "a8w4", "a16w4"] = "auto"
145
VLLM_ROCM_USE_AITER_RMSNORM: bool = True
146
VLLM_ROCM_USE_AITER_MLA: bool = True
147
VLLM_ROCM_AITER_MLA_ASM_PADDING: Literal["auto", "gluon", "asm"] = "auto"
@@ -1280,18 +1280,13 @@ environment_variables: dict[str, Callable[[], Any]] = {
1280
"VLLM_ROCM_USE_AITER_MOE": lambda: (
1281
os.getenv("VLLM_ROCM_USE_AITER_MOE", "True").lower() in ("true", "1")
1282
),
1283
- # Route K3 SiTU MXFP4 MoE through the FlyDSL SiTUv2 path (a4w4 fp4
1284
- # activations, separated gate/up layout) instead of default a16w4. vLLM
1285
- # sets AITER_SITUV2_A4W4 at init when this flag is on and clears any
1286
- # legacy AITER_SITUV2_A8W4 override (AITER checks A8W4 first).
1287
- # VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4 is a deprecated alias for existing
1288
- # recipes; it does not select a8w4 kernels.
1289
- # Needs AITER >= v0.1.20 (ROCm/aiter#4463) for the a4w4 dispatch flag
1290
- # and tuned kimik3_a4w4_*_fmoe.csv rows; otherwise FlyDSL uses heuristics.
1291
- "VLLM_ROCM_USE_AITER_MOE_SITUV2": lambda: (
1292
- os.getenv("VLLM_ROCM_USE_AITER_MOE_SITUV2", "0").lower() in ("true", "1")
1293
- or os.getenv("VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4", "0").lower()
1294
- in ("true", "1")
1283
+ # Activation dtype for the Kimi-K3 SiTU MXFP4 MoE (AITER FlyDSL SiTUv2):
1284
+ # auto (= a4w4), a4w4, a8w4 or a16w4. Legacy 1/0 mean a4w4/a16w4.
1285
+ "VLLM_ROCM_USE_AITER_MOE_SITUV2": env_with_choices(
1286
+ "VLLM_ROCM_USE_AITER_MOE_SITUV2",
1287
+ "auto",
1288
+ ["auto", "a4w4", "a8w4", "a16w4", "0", "1"],
1289
+ case_sensitive=False,
1290
),
1291
# MoE sorting dispatch policy for AITER fused MoE kernels.
1292
# 0 = auto (default): single-pass for small batches, multi-pass
vllm/model_executor/layers/fused_moe/experts/rocm_aiter_moe.py
+5
-4
@@ -385,10 +385,11 @@ def rocm_aiter_fused_experts(
385
386
gate_mode = ""
387
if activation == MoEActivation.SITU:
388
- # SiTUv2 flydsl (VLLM_ROCM_USE_AITER_MOE_SITUV2=1) uses a4w4
389
- # fp4 activations with separated gate/up weights (AITER #4463);
390
- # default a16w4 SiTU also stays separated.
391
- gate_mode = GateMode.SEPARATED.value
388
+ gate_mode = (
389
+ GateMode.INTERLEAVE.value
390
+ if rocm_aiter_ops.is_fused_moe_situv2_gate_up_interleaved()
391
+ else GateMode.SEPARATED.value
392
+ )
393
elif quant_config.use_mxfp4_w4a16:
394
gate_mode = GateMode.INTERLEAVE.value
395
elif activation_interleave is not None:
vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
+1
-2
@@ -1596,8 +1596,7 @@ def convert_weight_to_mxfp4_moe_kernel_format(
1596
1597
fp4_dtype = torch.float4_e2m1fn_x2
1598
e8m0_dtype = torch.float8_e8m0fnu
1599
- # SiTUv2 flydsl uses separated gate/up layout (a4w4).
1600
- guinterleave = False
1599
+ guinterleave = rocm_aiter_ops.is_fused_moe_situv2_gate_up_interleaved()
1600
w13 = rocm_aiter_ops.shuffle_weight_a16w4(
1601
w13_weight.data.view(fp4_dtype), 16, guinterleave
1602
)