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
183 lines
6.9 KiB
Python
183 lines
6.9 KiB
Python
################################################################################
|
|
# Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
# SPDX-License-Identifier: MIT
|
|
################################################################################
|
|
"""Characterization-suite shared configuration.
|
|
|
|
Adds the ``_codegen`` helper directory to ``sys.path`` so any characterization
|
|
suite can ``from codegen_harness import ...`` (the CPU-only assembly-emit
|
|
harness used by the codegen coverage suites), and exposes the cached
|
|
toolchain / cap-map / data-dir as session fixtures.
|
|
|
|
This file only *adds* an import path and read-only fixtures; it changes no
|
|
existing behavior.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
_CODEGEN_DIR = os.path.join(os.path.dirname(__file__), "_codegen")
|
|
if _CODEGEN_DIR not in sys.path:
|
|
sys.path.insert(0, _CODEGEN_DIR)
|
|
|
|
|
|
def _foreign_path_instantiable() -> bool:
|
|
"""Return True if a Windows-flavored ``pathlib.Path`` can be built here.
|
|
|
|
On POSIX, CPython refuses to instantiate ``WindowsPath`` (``NotImplementedError``
|
|
through 3.12, the ``NotImplementedError`` subclass ``UnsupportedOperation`` in
|
|
3.13+). Characterization tests that flip ``os.name`` to ``"nt"`` and let
|
|
production code construct a concrete ``pathlib.Path`` therefore raise inside the
|
|
function under test *and* inside pytest's own failure reporting, which builds
|
|
``Path(os.getcwd())`` while ``os.name`` is still ``"nt"`` -- taking down the
|
|
whole xdist worker with an INTERNALERROR. Detect the capability directly
|
|
rather than sniffing the interpreter version.
|
|
"""
|
|
from pathlib import Path
|
|
|
|
saved = os.name
|
|
try:
|
|
os.name = "nt"
|
|
Path("probe")
|
|
return True
|
|
except NotImplementedError:
|
|
return False
|
|
finally:
|
|
os.name = saved
|
|
|
|
|
|
def _snapshot_plugin_available() -> bool:
|
|
"""Return True if syrupy's ``snapshot`` fixture is available here.
|
|
|
|
The characterization suite asserts against syrupy snapshots via the
|
|
``snapshot`` fixture. The tox ``unit``/``coverage-unit`` environments install
|
|
syrupy, but the installed-artifact test tree (``share/hipblaslt/tensilelite``,
|
|
run by TheRock) executes against a leaner interpreter that does not ship
|
|
syrupy and does not receive this package's ``pyproject``/``tox`` dependency
|
|
declarations. There every ``snapshot``-using test errors at setup with
|
|
``fixture 'snapshot' not found``. Detect the capability directly so the suite
|
|
is cleanly skipped where the plugin is absent rather than erroring the run.
|
|
"""
|
|
import importlib.util
|
|
|
|
return importlib.util.find_spec("syrupy") is not None
|
|
|
|
|
|
def pytest_collection_modifyitems(config, items):
|
|
"""Skip capability-gated characterization tests where the env can't run them.
|
|
|
|
Two independent gates:
|
|
|
|
* ``nt_path_simulation`` tests flip ``os.name`` to ``"nt"`` and exercise
|
|
production code that constructs a ``pathlib.Path``. On any POSIX
|
|
interpreter this cannot succeed, so they run only where a Windows-flavored
|
|
``Path`` is instantiable.
|
|
* ``snapshot``-using tests require the syrupy plugin, which the
|
|
installed-artifact test environment does not provide; they run only where
|
|
syrupy is importable.
|
|
"""
|
|
skip_nt = None
|
|
if not _foreign_path_instantiable():
|
|
skip_nt = pytest.mark.skip(
|
|
reason="WindowsPath not instantiable on this interpreter; nt-path simulation skipped"
|
|
)
|
|
|
|
skip_snapshot = None
|
|
if not _snapshot_plugin_available():
|
|
skip_snapshot = pytest.mark.skip(
|
|
reason="syrupy not installed; snapshot characterization tests skipped"
|
|
)
|
|
|
|
if skip_nt is None and skip_snapshot is None:
|
|
return
|
|
|
|
for item in items:
|
|
if skip_nt is not None and "nt_path_simulation" in item.keywords:
|
|
item.add_marker(skip_nt)
|
|
if skip_snapshot is not None and "snapshot" in getattr(item, "fixturenames", ()):
|
|
item.add_marker(skip_snapshot)
|
|
|
|
|
|
@pytest.hookimpl(hookwrapper=True)
|
|
def pytest_runtest_makereport(item, call):
|
|
"""Tag a failed snapshot test so the terminal summary can route the author to
|
|
the golden-update policy.
|
|
|
|
Keys off the real ``snapshot`` fixture usage (not failure-text heuristics) and
|
|
records the tag on ``report.user_properties`` so it survives xdist worker ->
|
|
controller serialization (a plain module global would be lost under ``-n``).
|
|
"""
|
|
outcome = yield
|
|
report = outcome.get_result()
|
|
if (
|
|
report.when == "call"
|
|
and report.failed
|
|
and "snapshot" in getattr(item, "fixturenames", ())
|
|
):
|
|
report.user_properties.append(("char_snapshot_failure", True))
|
|
|
|
|
|
def pytest_terminal_summary(terminalreporter, exitstatus, config):
|
|
"""When a characterization snapshot test fails, print the snapshot-update
|
|
policy so a failing author never reaches for a blanket ``--snapshot-update``.
|
|
|
|
Driven by the ``char_snapshot_failure`` tag set in ``pytest_runtest_makereport``,
|
|
which gates on ``report.when == "call"`` -- so this fires on a call-phase failure
|
|
of a ``snapshot``-fixture test (usually a golden mismatch, occasionally an
|
|
unrelated error in the test body; the guidance is harmless in the latter case).
|
|
Setup-/teardown-phase errors are not tagged and do not trigger this banner.
|
|
"""
|
|
failed = terminalreporter.stats.get("failed", [])
|
|
nodeids = [
|
|
rep.nodeid
|
|
for rep in failed
|
|
if any(k == "char_snapshot_failure" for k, _ in getattr(rep, "user_properties", []))
|
|
]
|
|
if not nodeids:
|
|
return
|
|
|
|
bar = "=" * 78
|
|
write = terminalreporter.write_line
|
|
write("")
|
|
write(bar)
|
|
write("Characterization snapshot test failed (likely a golden mismatch)")
|
|
write("-" * 78)
|
|
write("These goldens pin TensileLite's current behavior as a refactor safety net.")
|
|
write("")
|
|
write("If this behavior change was NOT intended, you found a regression -- fix")
|
|
write("your code; do NOT touch the .ambr files.")
|
|
write("")
|
|
write("If it WAS intended, update ONLY the affected node(s) and review the diff:")
|
|
for nodeid in nodeids[:10]:
|
|
write(" pytest '%s' --snapshot-update" % nodeid)
|
|
if len(nodeids) > 10:
|
|
write(" ... and %d more" % (len(nodeids) - 10))
|
|
write("")
|
|
write("NEVER run a bare, suite-wide 'pytest --snapshot-update' -- it silently")
|
|
write("rewrites every golden and destroys the net.")
|
|
write("")
|
|
write(
|
|
"Policy (single source of truth): "
|
|
"Tensile/Tests/unit/characterization/README.md "
|
|
"-- 'Snapshot / golden discipline (governance)'"
|
|
)
|
|
write(bar)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def cg_assembler():
|
|
"""The CPU-only assembler (amdclang++); shared across codegen suites."""
|
|
from codegen_harness import get_assembler
|
|
|
|
return get_assembler()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def cg_isa_info_map():
|
|
"""The ISA capability map; shared across codegen suites."""
|
|
from codegen_harness import get_isa_info_map
|
|
|
|
return get_isa_info_map()
|