Files
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

169 lines
5.7 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
import sys
import os
import unittest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "codegen"))
from fmha.validation import validate_config, load_arch_specs
SPECS = load_arch_specs()
def _base_config(
family="fwd",
dtype="fp16",
arch="gfx950",
pipeline="qr_async",
hdim_q=128,
hdim_v=128,
**sig_overrides,
):
sig = {
"family": family,
"data_type": dtype,
"mode": "batch",
"vlayout": "r",
"hdim_q": hdim_q,
"hdim_v": hdim_v,
"mask": "no",
"bias": "no",
"lse": False,
"dropout": False,
"qscale": "no",
"rope": "none",
"logits": False,
"paged_kv": False,
"fp8_static_quant": False,
"skip_min_seqlen_q": False,
"sink": False,
"dbias": False,
"store_randval": False,
"deterministic": False,
"kv_memory_layout": "vectorized",
"kv_lookup_table": "sglang",
"page_size": 1,
}
sig.update(sig_overrides)
alg = {
"pipeline": pipeline,
"tile": [128, 128, 32, 128, 32, 128],
"wave": [4, 1, 1, 4, 1, 1, 1, 1, 1],
"warp": [32, 32, 16, 32, 32, 16, 16, 16, 16],
"padding": [True, True, True, True],
"block_per_cu": 1,
"num_wave_groups": 1,
"max_splits_log2": 0,
"max_seq_len_q": 0,
}
return {"signature": sig, "algorithm": alg, "arch": arch}
class TestValidateConfig(unittest.TestCase):
def test_valid_basic_config(self):
r = validate_config(_base_config(), SPECS)
self.assertTrue(r.valid, r.errors)
def test_unsupported_arch(self):
r = validate_config(_base_config(arch="gfx000"), SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("architecture" in e for e in r.errors))
def test_v3_hdim128_valid(self):
r = validate_config(_base_config(pipeline="v3", hdim_q=128, hdim_v=128), SPECS)
self.assertTrue(r.valid, r.errors)
def test_hdim_not_multiple_of_8(self):
r = validate_config(_base_config(hdim_q=65, hdim_v=128), SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("multiples of 8" in e for e in r.errors))
def test_bias_plus_logits_soft_cap(self):
r = validate_config(_base_config(bias="bias", logits=True), SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("logits_soft_cap" in e for e in r.errors))
def test_hdim_192_128_with_bias(self):
r = validate_config(_base_config(hdim_q=192, hdim_v=128, bias="bias"), SPECS)
has_issue = any("(192,128)" in e for e in r.errors) or any(
"(192,128)" in w for w in r.warnings
)
self.assertTrue(has_issue)
def test_hdim_192_128_with_dropout(self):
r = validate_config(_base_config(hdim_q=192, hdim_v=128, dropout=True), SPECS)
has_issue = any("(192,128)" in e for e in r.errors) or any(
"(192,128)" in w for w in r.warnings
)
self.assertTrue(has_issue)
def test_appendkv_must_use_appendkv_pipeline(self):
cfg = _base_config(family="fwd_appendkv", pipeline="qr_async")
r = validate_config(cfg, SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("appendkv pipeline" in e for e in r.errors))
def test_pagedkv_requires_qr_pagedkv_pipeline(self):
cfg = _base_config(family="fwd_pagedkv", pipeline="qr_async", paged_kv=True)
r = validate_config(cfg, SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("qr_pagedkv" in e for e in r.errors))
def test_batch_prefill_requires_group_mode(self):
cfg = _base_config(
family="batch_prefill",
pipeline="qr_async",
mode="batch",
paged_kv=True,
page_size=64,
)
cfg["signature"]["mode"] = "batch"
r = validate_config(cfg, SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("group mode" in e for e in r.errors))
def test_batch_prefill_valid_group(self):
cfg = _base_config(
family="batch_prefill", pipeline="qr_async", paged_kv=True, page_size=64
)
cfg["signature"]["mode"] = "group"
r = validate_config(cfg, SPECS)
self.assertTrue(r.valid, r.errors)
def test_splitkv_combine_bn1_must_be_32(self):
cfg = _base_config(family="fwd_splitkv_combine", pipeline="qr")
cfg["algorithm"]["tile"][3] = 64
r = validate_config(cfg, SPECS)
self.assertFalse(r.valid)
self.assertTrue(any("bn1" in e for e in r.errors))
def test_bwd_dot_do_o_bm0_128_accepted(self):
cfg = _base_config(family="bwd_dot_do_o", pipeline="qr")
cfg["algorithm"]["tile"][0] = 128
r = validate_config(cfg, SPECS)
# bwd_dot_do_o with bm0=128 is now valid (relaxed from strict bm0=64)
self.assertTrue(r.valid, r.errors)
def test_mask_types_all_valid(self):
for mask in ["no", "top_left", "bottom_right", "generic"]:
r = validate_config(_base_config(mask=mask), SPECS)
self.assertTrue(r.valid, f"mask={mask}: {r.errors}")
class TestMaskDistinction(unittest.TestCase):
"""Verify that top_left and bottom_right are distinct after fix."""
def test_mask_canonical_distinguishes(self):
from fmha.symbol_map import canonical_mask, MASK_TO_INT
self.assertEqual(canonical_mask("top_left"), "top_left")
self.assertEqual(canonical_mask("bottom_right"), "bottom_right")
self.assertNotEqual(MASK_TO_INT["top_left"], MASK_TO_INT["bottom_right"])
if __name__ == "__main__":
unittest.main()