Files
TheRock/rocm-libraries/shared/stinkytofu/python_module/tests/test_comgr.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

273 lines
9.1 KiB
Python

# Copyright Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Tests for comgr-based toolchain capability probing."""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../build/lib"))
import stinkytofu
class TestComgrSupport:
def test_has_comgr_support(self):
assert stinkytofu.hasComgrSupport() is True
class TestProbeToolchainCaps:
def test_gfx1250_returns_dict(self):
caps = stinkytofu.probeToolchainCaps([12, 5, 0])
assert isinstance(caps, dict)
assert "VgprMsbMode" in caps
def test_gfx1250_vgpr_msb_mode_non_zero(self):
caps = stinkytofu.probeToolchainCaps([12, 5, 0])
assert caps["VgprMsbMode"] != stinkytofu.VgprMsbMode.NONE.value
def test_gfx1250_vgpr_msb_mode_is_msb8_or_msb16(self):
caps = stinkytofu.probeToolchainCaps([12, 5, 0])
assert caps["VgprMsbMode"] in (
stinkytofu.VgprMsbMode.MSB8.value,
stinkytofu.VgprMsbMode.MSB16.value,
)
class TestVgprMsbModeEnum:
def test_enum_values(self):
assert stinkytofu.VgprMsbMode.NONE.value == 0
assert stinkytofu.VgprMsbMode.MSB8.value == 1
assert stinkytofu.VgprMsbMode.MSB16.value == 2
class TestTryAssemble:
"""Tests for the tryAssemble Python binding."""
def test_valid_instruction(self):
assert stinkytofu.tryAssemble("v_mov_b32 v0, v1", [12, 5, 0]) is True
def test_invalid_instruction(self):
assert stinkytofu.tryAssemble("v_nonexistent_op v0, v1", [12, 5, 0]) is False
class TestGetHardwareCaps:
def test_gfx1250_returns_all_dicts(self):
caps = stinkytofu.getHardwareCaps([12, 5, 0])
assert isinstance(caps, dict)
for key in ("asmCaps", "archCaps", "regCaps", "asmBugs"):
assert key in caps
assert isinstance(caps[key], dict)
def test_gfx1250_asm_bugs(self):
bugs = stinkytofu.getHardwareCaps([12, 5, 0])["asmBugs"]
assert isinstance(bugs["ExplicitCO"], bool)
assert isinstance(bugs["ExplicitNC"], bool)
def test_idempotent(self):
caps1 = stinkytofu.getHardwareCaps([12, 5, 0])
caps2 = stinkytofu.getHardwareCaps([12, 5, 0])
assert caps1["asmCaps"] == caps2["asmCaps"]
assert caps1["archCaps"] == caps2["archCaps"]
class TestAsmCapsVsCompiler:
"""Verify asmCaps values against actual compiler assembly probes.
For mnemonic-based caps, we check that the cap is 1 iff tryAssemble
succeeds for the corresponding instruction. For modifier/encoding
caps we use the exact assembly strings that HardwareCaps.cpp uses.
"""
ARCH = [12, 5, 0]
@staticmethod
def _asm(s):
return stinkytofu.tryAssemble(s, TestAsmCapsVsCompiler.ARCH)
@staticmethod
def _asm_any(*strs):
return any(stinkytofu.tryAssemble(s, TestAsmCapsVsCompiler.ARCH) for s in strs)
def _caps(self):
return stinkytofu.getHardwareCaps(self.ARCH)["asmCaps"]
# -- Mnemonic-only caps --
def test_has_explicit_co(self):
asm = self._caps()
assert asm["HasExplicitCO"] == int(self._asm("v_add_co_u32 v0, vcc_lo, v1, v2"))
def test_has_explicit_nc(self):
asm = self._caps()
assert asm["HasExplicitNC"] == int(self._asm("v_add_nc_u32 v0, v1, v2"))
def test_has_mfma(self):
asm = self._caps()
expected = int(
self._asm_any(
"v_mfma_f32_32x32x2bf16 a[0:31], v0, v1, a[0:31]",
"v_mfma_f32_32x32x1_2b_f32 a[0:31], v0, v1, a[0:31]",
)
)
assert asm["HasMFMA"] == expected
def test_has_wmma(self):
asm = self._caps()
expected = int(
self._asm_any(
"v_wmma_f32_16x16x16_f16 v[0:7], v[8:15], v[16:23], v[0:7]",
"v_wmma_f32_16x16x32_bf16 v[0:7], v[8:15], v[16:23], v[0:7]",
"v_wmma_f32_16x16x4_f32 v[0:7], v[8:15], v[16:23], v[0:7]",
)
)
assert asm["HasWMMA"] == expected
def test_has_new_barrier(self):
asm = self._caps()
assert asm["HasNewBarrier"] == int(self._asm("s_barrier_wait -1"))
def test_has_tdm(self):
asm = self._caps()
# HasTDM is a mnemonic-lookup cap; just verify it's a valid int
assert asm["HasTDM"] in (0, 1)
def test_s_delay_alu(self):
asm = self._caps()
assert asm["s_delay_alu"] == int(self._asm("s_delay_alu 0"))
# -- Modifier/encoding caps (comgr-probed) --
def test_has_direct_to_lds(self):
asm = self._caps()
expected = int(
self._asm_any(
"buffer_load_dword v36, s[24:27], s28 offen offset:0 lds",
"buffer_load_b32 v36, s[24:27], s28 offen offset:0 lds",
)
)
assert asm["HasDirectToLds"] == expected
def test_has_wmma_v1(self):
asm = self._caps()
expected = int(
self._asm("v_wmma_f32_16x16x16_f16 v[0:3], v[8:15], v[16:23], v[0:3]")
)
assert asm["HasWMMA_V1"] == expected
def test_has_wmma_v2(self):
asm = self._caps()
# V2 uses 2-register source, but is overridden to 0 if V3 is present
v2_asm = int(
self._asm("v_wmma_f32_16x16x16_f16 v[0:3], v[8:9], v[16:17], v[0:3]")
)
v3 = asm["HasWMMA_V3"]
expected = 0 if v3 else v2_asm
assert asm["HasWMMA_V2"] == expected
def test_has_glc_modifier(self):
asm = self._caps()
expected = int(
self._asm_any(
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], 0, offen offset:0, glc",
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], null, offen offset:0, glc",
)
)
assert asm["HasGLCModifier"] == expected
def test_has_scope_modifier(self):
asm = self._caps()
expected = int(
self._asm_any(
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], 0, offen offset:0, scope:SCOPE_DEV",
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], null offen offset:0, scope:SCOPE_DEV",
)
)
assert asm["HasSCOPEModifier"] == expected
def test_v_fmac_f16(self):
asm = self._caps()
assert asm["v_fmac_f16"] == int(self._asm("v_fma_f16 v47, v36, v34"))
def test_vop3_v_dot4_i32_i8(self):
asm = self._caps()
assert asm["VOP3v_dot4_i32_i8"] == int(
self._asm("v_dot4_i32_i8 v47, v36, v34, v47")
)
def test_has_cvt_fp8_to_f16(self):
asm = self._caps()
assert asm["HasCvtFP8toF16"] == int(
self._asm("v_cvt_f16_fp8 v[0], v[1] byte_sel:2")
)
# -- Wait count limits (derived from instruction support) --
def test_separate_vmcnt_and_limits(self):
asm = self._caps()
has_loadcnt = int(self._asm("s_wait_loadcnt 0"))
has_storecnt = int(self._asm("s_wait_storecnt 0"))
assert asm["SeparateVMcnt"] == (has_loadcnt and has_storecnt)
if asm["SeparateVMcnt"]:
assert asm["MaxLoadcnt"] == 63
assert asm["MaxStorecnt"] == 63
def test_has_xcnt(self):
asm = self._caps()
assert asm["HasXcnt"] == int(self._asm("s_wait_xcnt 0"))
if asm["HasXcnt"]:
assert asm["MaxXcnt"] == 63
def test_has_th_modifier(self):
asm = self._caps()
expected = int(
self._asm_any(
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], 0 offen offset:0 th:TH_LOAD_NT",
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], null offen offset:0 th:TH_LOAD_NT",
)
)
assert asm["HasTHModifier"] == expected
def test_has_nv_modifier(self):
asm = self._caps()
expected = int(
self._asm_any(
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], 0 offen offset:0 nv",
"buffer_load_dwordx4 v[10:13], v[0], s[0:3], null offen offset:0 nv",
)
)
assert asm["HasNVModifier"] == expected
def test_has_global_prefetch(self):
asm = self._caps()
expected = int(
self._asm("global_prefetch_b8 v[0:1], off scope:SCOPE_SE th:TH_LOAD_NT")
)
assert asm["HasGlobalPrefetch"] == expected
class TestArchCaps:
"""Verify archCaps values for gfx1250 are correct based on ISA version checks."""
def test_gfx1250_known_values(self):
arch = stinkytofu.getHardwareCaps([12, 5, 0])["archCaps"]
assert arch["HasWave32"] == 1
assert arch["HasSchedMode"] == 1
assert arch["NoSDWA"] == 1
assert arch["HasEccHalf"] == 1
assert arch["DeviceLDS"] == 327680
assert arch["CMPXWritesSGPR"] == 0
assert arch["HasInvWbDevFences"] == 1
assert arch["MaxSgprPreload"] == 32
assert arch["LDSBankCount"] == 64
class TestRegCaps:
"""Verify regCaps values for gfx1250 are correct."""
def test_gfx1250_known_values(self):
reg = stinkytofu.getHardwareCaps([12, 5, 0])["regCaps"]
assert reg["MaxVgpr"] == 1024
assert reg["MaxSgpr"] == 106
assert reg["PhysicalMaxVgpr"] == 1024
assert reg["PhysicalMaxVgprCU"] == 4096 * 32