Files
wehub-resource-sync e9a2f726c9
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:29:51 +08:00

128 lines
4.4 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""Tests for NAX (M5 tensor unit) detection and qmm dispatch gating."""
from __future__ import annotations
import types
import pytest
import omlx.custom_kernels.qwen35_prefill.fast as fast
from omlx.custom_kernels.nax import is_nax_available
@pytest.fixture(autouse=True)
def _fresh_nax_state(monkeypatch):
monkeypatch.setattr(fast, "_nax_available_cache", None)
monkeypatch.setattr(fast, "_stock_nax_cache", None)
monkeypatch.setattr(fast, "_qmm_nax_cache", None)
monkeypatch.delenv("OMLX_NAX", raising=False)
monkeypatch.delenv("OMLX_QWEN35_QMM_NAX", raising=False)
yield
@pytest.mark.parametrize(
("version", "arch", "expected"),
[
("26.2", "applegpu_g17s", True),
("26.2.1", "applegpu_g17d", True),
("26.2", "applegpu_g18p", True),
("26.2", "applegpu_g17p", False),
("26.2", "applegpu_g15d", False),
("26.1", "applegpu_g17s", False),
("15.5", "applegpu_g17s", False),
("26.2", "applegpu_gXYs", False),
("26.2", "", False),
("garbage", "applegpu_g17s", False),
],
)
def test_nax_fallback_mirrors_mlx_gate(version, arch, expected):
assert fast._nax_available_fallback(version, arch) is expected
def test_is_nax_available_env_override(monkeypatch):
monkeypatch.setenv("OMLX_NAX", "1")
assert fast.is_nax_available() is True
monkeypatch.setenv("OMLX_NAX", "0")
assert fast.is_nax_available() is False
def test_is_nax_available_uses_fallback_without_ext(monkeypatch):
monkeypatch.setattr(fast, "_EXT_HAS_NAX", False)
monkeypatch.setattr(fast, "_nax_available_fallback", lambda: True)
monkeypatch.setattr(fast, "_stock_mlx_has_nax", lambda: True)
assert fast.is_nax_available() is True
def test_is_nax_available_requires_stock_nax_kernels(monkeypatch):
# NAX hardware with a no-NAX mlx wheel (e.g. the macosx_15 sequoia
# bundle): stock stays classic, so route-to-stock must not engage.
monkeypatch.setattr(fast, "_EXT_HAS_NAX", False)
monkeypatch.setattr(fast, "_nax_available_fallback", lambda: True)
monkeypatch.setattr(fast, "_stock_mlx_has_nax", lambda: False)
assert fast.is_nax_available() is False
def test_stock_mlx_probe_scans_metallib(tmp_path):
with_nax = tmp_path / "with_nax.metallib"
with_nax.write_bytes(b"\x00" * 100 + b"affine_qmm_t_nax_bfloat16_t" + b"\x00" * 100)
assert fast._stock_mlx_has_nax(with_nax) is True
without_nax = tmp_path / "without_nax.metallib"
without_nax.write_bytes(b"\x00" * 100 + b"affine_qmm_t_classic" + b"\x00" * 100)
assert fast._stock_mlx_has_nax(without_nax) is False
# Absent metallib (JIT build) falls back to the hardware-only gate.
assert fast._stock_mlx_has_nax(tmp_path / "missing.metallib") is True
def test_stock_mlx_probe_finds_needle_across_chunks(tmp_path, monkeypatch):
lib = tmp_path / "boundary.metallib"
chunk = 1 << 23
needle = b"affine_qmm_t_nax"
# Place the needle straddling the first chunk boundary.
lib.write_bytes(b"\x00" * (chunk - 8) + needle + b"\x00" * 64)
assert fast._stock_mlx_has_nax(lib) is True
def test_nax_shim_reexports_fast_impl():
assert is_nax_available is fast.is_nax_available
def test_qmm_nax_kwargs_empty_for_pre_nax_ext(monkeypatch):
monkeypatch.setattr(fast, "_EXT_HAS_NAX", False)
assert fast._qmm_nax_kwargs() == {}
def test_qmm_nax_kwargs_on_nax_machine(monkeypatch):
fake_ext = types.SimpleNamespace(
is_nax_available=lambda: True,
nax_qmm_kernels_built=lambda: True,
)
monkeypatch.setattr(fast, "_ext", fake_ext)
monkeypatch.setattr(fast, "_EXT_HAS_NAX", True)
kwargs = fast._qmm_nax_kwargs()
assert kwargs["use_nax"] is True
assert kwargs["nax_variant"] == fast.QMM_NAX_VARIANT
def test_qmm_nax_env_kill_switch(monkeypatch):
fake_ext = types.SimpleNamespace(
is_nax_available=lambda: True,
nax_qmm_kernels_built=lambda: True,
)
monkeypatch.setattr(fast, "_ext", fake_ext)
monkeypatch.setattr(fast, "_EXT_HAS_NAX", True)
monkeypatch.setenv("OMLX_QWEN35_QMM_NAX", "0")
assert fast._qmm_nax_kwargs()["use_nax"] is False
def test_qmm_nax_disabled_without_kernels(monkeypatch):
fake_ext = types.SimpleNamespace(
is_nax_available=lambda: True,
nax_qmm_kernels_built=lambda: False,
)
monkeypatch.setattr(fast, "_ext", fake_ext)
monkeypatch.setattr(fast, "_EXT_HAS_NAX", True)
assert fast._qmm_nax_kwargs()["use_nax"] is False