Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/Tensile/Tests/unit/test_WmmaSourceCacheOpt.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

279 lines
9.5 KiB
Python

# Copyright Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Unit tests for zigzag WMMA tile ordering in emit_mfma."""
import re
import pytest
from types import SimpleNamespace
from unittest.mock import MagicMock
from Tensile.Components.Subtile.LogicalScheduler import (
MFMATileRange, ReadGranularity, SchedulerConfig, MFMAPlacement,
)
from Tensile.Components.Subtile.InstructionEmitter import _zigzag_order
from Tensile.Components.Subtile.InstructionEmitter import InstructionEmitter
from Tensile.Components.Subtile.Kernel import TileInfo, AB_B16, CD_F32
# ── Helpers ─────────────────────────────────────────────────────
_COMMENT_RE = re.compile(r"MFMA C\[(\d+),(\d+)\]")
def _extract_ab_pairs(instructions):
"""Return [(a, b), ...] from MFMA instruction comments."""
pairs = []
for inst in instructions:
m = _COMMENT_RE.search(str(inst))
if m:
pairs.append((int(m.group(1)), int(m.group(2))))
return pairs
def _mock_dtype(num_bytes=2):
mock = MagicMock()
mock.numBytes.return_value = num_bytes
mock.numRegisters.return_value = num_bytes / 4
mock.isBFloat16.return_value = (num_bytes == 2)
mock.is8bitFloat.return_value = (num_bytes == 1)
return mock
def _make_kernel(numM, numN):
"""Minimal kernel dict for emit_mfma."""
dtype = _mock_dtype(2)
return {
"MacroTile0": numM * 16,
"MacroTile1": numN * 16,
"MacroTileA": numM * 16,
"MacroTileB": numN * 16,
"DepthU": 64,
"_DepthUA": 64,
"_DepthUB": 64,
"MatrixInstM": 16,
"MatrixInstN": 16,
"MatrixInstK": 32,
"MatrixInstB": 1,
"MIInputPerThreadA": 8,
"MIInputPerThreadB": 8,
"MIWaveGroup": [1, 1],
"WavefrontSize": 32,
"SourceSwap": False,
"MIArchVgpr": True,
"ProblemType": {
"DataTypeA": dtype,
"DataTypeB": dtype,
"ComputeDataType": _mock_dtype(4),
"MXBlockA": 0,
"MXBlockB": 0,
},
}
def _make_emitter(numM, numN):
"""Build a minimal InstructionEmitter that can call emit_mfma."""
from rocisa.register import RegisterPool
from rocisa.enum import RegisterType
kernel = _make_kernel(numM, numN)
writer = SimpleNamespace()
writer.vgprPool = RegisterPool(0, RegisterType.Vgpr,
defaultPreventOverflow=False, printRP=False)
writer.sgprPool = RegisterPool(0, RegisterType.Sgpr,
defaultPreventOverflow=False, printRP=False)
writer.agprPool = RegisterPool(0, RegisterType.Accvgpr,
defaultPreventOverflow=False, printRP=False)
writer.states = SimpleNamespace(
archCaps={"LDSBankCount": 64, "LDSBankWidth": 4},
asmCaps={"HasWMMA_V3": True},
regCaps={"MaxSgpr": 106, "MaxVgpr": 256, "PhysicalMaxVgpr": 512},
subtileLdsSwizzle=False,
)
tileInfoA = TileInfo(AB_B16, 'A', writer, kernel)
tileInfoB = TileInfo(AB_B16, 'B', writer, kernel)
dtileInfo = TileInfo(CD_F32, 'D', writer, kernel)
# Allocate VGPR tiles for A, B, D
tileInfoA.allocVgprTileRegisters_legacy(writer, kernel)
tileInfoB.allocVgprTileRegisters_legacy(writer, kernel)
dtileInfo.allocVgprTileRegisters_legacy(writer, kernel)
config = SchedulerConfig(
numMFMATilesM=numM,
numMFMATilesN=numN,
numSubIterK=2,
lrA=ReadGranularity(mn=1, k=1),
lrB=ReadGranularity(mn=1, k=1),
grA=ReadGranularity(mn=1, k=2),
grB=ReadGranularity(mn=1, k=2),
)
emitter = InstructionEmitter(
writer, kernel, config,
tileInfoA, tileInfoB, dtileInfo,
tileInfoA.vgprTiles, tileInfoB.vgprTiles,
)
return emitter
def _make_placement(numM, numN, subIterK=0):
"""Create an MFMAPlacement spanning all M and N tiles at one subIterK."""
placement = MFMAPlacement(
subIterK=subIterK,
tileA=MFMATileRange(subIterK, subIterK + 1, 0, numM),
tileB=MFMATileRange(subIterK, subIterK + 1, 0, numN),
)
# Identity tile map: tileId -> vgprTileId (one unroll iter)
placement.vgpr_tile_maps = {
'A': [{i: i for i in range(numM)}],
'B': [{i: i for i in range(numN)}],
}
return placement
@pytest.fixture(scope="module", autouse=True)
def _init_rocisa():
from gpu_test_helpers import init_rocisa
init_rocisa(target="gfx1250", wavesize=32)
# ── Tests ───────────────────────────────────────────────────────
class TestZigzagOrder:
"""Verify the _zigzag_order helper produces correct zigzag-matrix traversal."""
def test_1x1(self):
assert _zigzag_order(1, 1) == [(0, 0)]
def test_2x2(self):
assert _zigzag_order(2, 2) == [(0, 0), (0, 1), (1, 1), (1, 0)]
def test_3x3(self):
expected = [
(0, 0), (0, 1), (0, 2),
(1, 2), (1, 1), (1, 0),
(2, 0), (2, 1), (2, 2),
]
assert _zigzag_order(3, 3) == expected
def test_4x4(self):
result = _zigzag_order(4, 4)
assert len(result) == 16
assert len(set(result)) == 16 # all unique
# every consecutive pair shares exactly one coordinate
for i in range(1, len(result)):
r0, c0 = result[i - 1]
r1, c1 = result[i]
assert (r0 == r1) != (c0 == c1), (
f"Step {i}: ({r0},{c0})->({r1},{c1}) must share exactly one coord"
)
def test_2x4_rectangular(self):
result = _zigzag_order(2, 4)
assert len(result) == 8
assert len(set(result)) == 8
# first row left-to-right, then down, then bottom row right-to-left, then up
assert result == [
(0, 0), (0, 1), (0, 2), (0, 3),
(1, 3), (1, 2), (1, 1), (1, 0),
]
def test_4x2_rectangular(self):
result = _zigzag_order(4, 2)
assert len(result) == 8
assert len(set(result)) == 8
assert result == [
(0, 0), (0, 1),
(1, 1), (1, 0),
(2, 0), (2, 1),
(3, 1), (3, 0),
]
def test_1xN_single_row(self):
assert _zigzag_order(1, 5) == [(0, c) for c in range(5)]
def test_Nx1_single_col(self):
assert _zigzag_order(5, 1) == [(r, 0) for r in range(5)]
class TestZigzagEmitMfma:
"""Verify emit_mfma produces zigzag-ordered (a,b) pairs when enabled."""
def test_longer_a_sweeps_along_a(self):
"""When A > B, the contiguous zig sweeps along A (longer dim)."""
numM, numN = 4, 3
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
# Sweep along A: outer=B(3), inner=A(4)
expected = [(c, r) for r, c in _zigzag_order(numN, numM)]
assert pairs == expected
def test_longer_b_sweeps_along_b(self):
"""When B > A, the contiguous zig sweeps along B (longer dim)."""
numM, numN = 3, 4
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
# Sweep along B: outer=A(3), inner=B(4)
expected = [(r, c) for r, c in _zigzag_order(numM, numN)]
assert pairs == expected
def test_every_pair_shares_one_operand(self):
"""Every consecutive WMMA pair must share exactly one operand (A or B)."""
numM, numN = 4, 4
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
for i in range(1, len(pairs)):
prev_a, prev_b = pairs[i - 1]
cur_a, cur_b = pairs[i]
shared_a = (prev_a == cur_a)
shared_b = (prev_b == cur_b)
assert shared_a != shared_b, (
f"Step {i}: ({prev_a},{prev_b})->({cur_a},{cur_b}) "
f"must share exactly one operand"
)
def test_single_b_tile_unaffected(self):
"""With only 1 B tile, zigzag falls back to raster."""
numM, numN = 4, 1
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
expected = [(a, 0) for a in range(numM)]
assert pairs == expected
def test_single_a_tile_unaffected(self):
"""With only 1 A tile, zigzag falls back to raster."""
numM, numN = 1, 4
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
expected = [(0, b) for b in range(numN)]
assert pairs == expected
def test_2x2_zigzag(self):
"""Minimal 2x2 case: zigzag snake (A==B, sweeps along A)."""
numM, numN = 2, 2
emitter = _make_emitter(numM, numN)
placement = _make_placement(numM, numN)
insts = emitter.emit_mfma(placement, unroll_iter=0)
pairs = _extract_ab_pairs(insts)
# A>=B so sweep along A: [(0,0),(1,0),(1,1),(0,1)]
assert pairs == [(0, 0), (1, 0), (1, 1), (0, 1)]