Skip to content

Commit c6d6abd

Browse files
Fangzhou-Aicodex
andcommitted
fix(flydsl): handle remainder workgroups in MoE XCD swizzle
Distribute remainder workgroups across XCD ranges so non-divisible grids remain a complete permutation. The previous floor-division mapping duplicated workgroups and omitted the tail of affected grids. Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Fangzhou Ai <fangzhouai@gmail.com>
1 parent ad2f051 commit c6d6abd

3 files changed

Lines changed: 76 additions & 5 deletions

File tree

aiter/ops/flydsl/kernels/mixed_moe_gemm_2stage.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def supports_bf16_global_atomics(arch: str) -> bool:
6464
tile_chunk_coord_i32,
6565
unpack_b_mxfp4_bf16,
6666
)
67+
from aiter.ops.flydsl.moe_common import xcd_swizzle_workgroup_id
6768

6869

6970
@contextmanager
@@ -563,8 +564,15 @@ def ptr_buffer_resource(ptr, num_records_bytes):
563564
num_wgs = gx * gy
564565

565566
c_xcds = arith.constant(NUM_XCDS_S1, index=True)
566-
wgs_per_xcd = num_wgs // c_xcds
567-
wgid = (linear_id % c_xcds) * wgs_per_xcd + (linear_id // c_xcds)
567+
wgid = xcd_swizzle_workgroup_id(
568+
linear_id,
569+
num_wgs,
570+
c_xcds,
571+
divide=lambda lhs, rhs: lhs // rhs,
572+
minimum=lambda lhs, rhs: arith.select(
573+
arith.cmpi(CmpIPredicate.ult, lhs, rhs), lhs, rhs
574+
),
575+
)
568576

569577
WGM_S1 = xcd_swizzle
570578
c_wgm = arith.constant(WGM_S1, index=True)
@@ -3366,8 +3374,15 @@ def check_c_k_valid_gate(base_k):
33663374
num_wgs = gx * gy
33673375

33683376
c_xcds = arith.constant(NUM_XCDS_S, index=True)
3369-
wgs_per_xcd = num_wgs // c_xcds
3370-
wgid = (linear_id % c_xcds) * wgs_per_xcd + (linear_id // c_xcds)
3377+
wgid = xcd_swizzle_workgroup_id(
3378+
linear_id,
3379+
num_wgs,
3380+
c_xcds,
3381+
divide=lambda lhs, rhs: lhs // rhs,
3382+
minimum=lambda lhs, rhs: arith.select(
3383+
arith.cmpi(CmpIPredicate.ult, lhs, rhs), lhs, rhs
3384+
),
3385+
)
33713386

33723387
WGM_S = xcd_swizzle
33733388
c_wgm = arith.constant(WGM_S, index=True)

aiter/ops/flydsl/moe_common.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
# SPDX-License-Identifier: MIT
22
# Copyright (C) 2024-2026, Advanced Micro Devices, Inc. All rights reserved.
33

4-
"""Common types shared across MoE FlyDSL kernel modules."""
4+
"""Common helpers and types shared across MoE FlyDSL kernel modules."""
55

66
from enum import Enum
77

88

9+
def xcd_swizzle_workgroup_id(linear_id, num_workgroups, num_xcds, divide, minimum):
10+
"""Map round-robin workgroup IDs into balanced contiguous XCD ranges."""
11+
workgroups_per_xcd = divide(num_workgroups, num_xcds)
12+
remainder = num_workgroups % num_xcds
13+
xcd_id = linear_id % num_xcds
14+
local_id = divide(linear_id, num_xcds)
15+
return xcd_id * workgroups_per_xcd + minimum(xcd_id, remainder) + local_id
16+
17+
918
class GateMode(str, Enum):
1019
"""Gate/Up computation strategy for stage1 GEMM.
1120
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2024-2026, Advanced Micro Devices, Inc. All rights reserved.
3+
4+
import importlib.util
5+
import operator
6+
import unittest
7+
from pathlib import Path
8+
9+
_MOE_COMMON_PATH = (
10+
Path(__file__).resolve().parents[2] / "aiter/ops/flydsl/moe_common.py"
11+
)
12+
_SPEC = importlib.util.spec_from_file_location("moe_common", _MOE_COMMON_PATH)
13+
_MOE_COMMON = importlib.util.module_from_spec(_SPEC)
14+
_SPEC.loader.exec_module(_MOE_COMMON)
15+
xcd_swizzle_workgroup_id = _MOE_COMMON.xcd_swizzle_workgroup_id
16+
17+
18+
class TestMoeXcdSwizzle(unittest.TestCase):
19+
def assert_permutation(self, num_workgroups):
20+
mapped_ids = [
21+
xcd_swizzle_workgroup_id(
22+
linear_id,
23+
num_workgroups,
24+
8,
25+
divide=operator.floordiv,
26+
minimum=min,
27+
)
28+
for linear_id in range(num_workgroups)
29+
]
30+
self.assertTrue(
31+
all(0 <= mapped_id < num_workgroups for mapped_id in mapped_ids)
32+
)
33+
self.assertEqual(len(set(mapped_ids)), num_workgroups)
34+
35+
def test_divisible_and_remainder_grids_are_permutations(self):
36+
for num_workgroups in range(1, 257):
37+
with self.subTest(num_workgroups=num_workgroups):
38+
self.assert_permutation(num_workgroups)
39+
40+
def test_dsv4_stage2_grids_are_permutations(self):
41+
for num_workgroups in (28 * 400, 28 * 399):
42+
with self.subTest(num_workgroups=num_workgroups):
43+
self.assert_permutation(num_workgroups)
44+
45+
46+
if __name__ == "__main__":
47+
unittest.main()

0 commit comments

Comments
 (0)