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
169 lines
5.7 KiB
Python
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()
|