Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions dnn-providers/hip-kernel-provider/rocke/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,50 @@ tests; an older local compiler failure is separate evidence. Review skipped
tests explicitly: Torch-free execution, missing native fixtures, and unavailable
GPUs each leave different coverage gaps. Host pytest is not a full GPU job replay.

#### 5.1.3 Writing native recipe replay tests

Native replay APIs can hide a source-build dependency. In particular,
[`online.recipe_cbor_to_llvm()`](platform/python/rocke/portable_ir/src/online.py)
calls `online.load()`, which calls `build_lib()` when it finds no prebuilt shared
library. A test can pass in a source checkout or with a cached library, then fail
in an installed artifact because the source tree and `CMakeLists.txt` are absent.
Do not let replay test setup implicitly configure or build native code.

When adding or changing a native replay test:

- Build the native artifact during build/setup, from the same revision as the
Python oracle. Run a prebuilt replay CLI, or supply a prebuilt shared-library
path explicitly before calling the online API. Never fall back to a cached
library or an automatic source build to make the test pass.
- If the prebuilt CLI is unset or missing, skip the native replay lane with a
reason identifying the missing artifact, following the existing portable-IR
tests. Once present, execution errors and IR mismatches are failures; do not
catch them as capability skips. Keep independent Python coverage enabled.
- Let the launcher supply artifact paths. Installed CTest paths must be relative
to its working directory so relocation works. Do not infer artifact presence
or location from test-file paths, nearby source files, or conventional build
directories. Install required content through CMake and the artifact manifest.
- Keep a suite-specific fixture local to its module. Do not mutate shared
environment settings during fixture setup or add an autouse fixture that
changes other suites' native-lane discovery or skips. Shared launcher wiring
or fixtures need an intentional consumer contract and validation of every
affected suite.

The existing replay CLI target is `rocke_portable_ir_replay_cli`; its installed
location is `tests/portable_ir/`. `ROCKE_REPLAY_CLI` is the single launcher setting
for native CLI replay, including TF32 and the portable-IR suites. Installed CTest
supplies the relative executable path once for the pytest run, enabling all
consumers of that artifact.

For source execution, build the target first and supply its executable through
`ROCKE_REPLAY_CLI`. Reuse this setting for new replay consumers rather than adding
a kernel-specific setting. When changing its launcher wiring, validate every
consumer, including suites whose native lanes previously skipped. Check absent
and present artifacts, a broken executable, and unrelated suites' skips.
Repeat the native lane in a clean
relocated install without source directories or native caches available; a
source-only pass cannot establish installed-artifact support.

## 6. Invariants & contracts

Cross-cutting properties every change must preserve:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ if(ROCKE_INSTALL_TESTS)
string(APPEND _ROCKE_INSTALLED_CTEST_ENTRIES
"set_tests_properties(rocke_pytest PROPERTIES\n"
" LABELS \"ckc\\;python\\;quick\"\n"
" ENVIRONMENT \"PYTHONPATH=.\"\n"
" ENVIRONMENT \"PYTHONPATH=.;ROCKE_REPLAY_CLI=${ROCKE_TEST_CTEST_REL}tests/portable_ir/rocke_portable_ir_replay_cli${CMAKE_EXECUTABLE_SUFFIX}\"\n"
" TIMEOUT 300)\n")
endif()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ if(BUILD_TESTING)
if(UNIX)
target_link_libraries(rocke_portable_ir_replay_cli PRIVATE m)
endif()
# Python recipe tests need the native VM in relocated test artifacts.
install(TARGETS rocke_portable_ir_replay_cli
RUNTIME DESTINATION "${ROCKE_TEST_INSTALL_DIR}/tests/portable_ir")
endif()

# --- instances layer --------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Logical TF32 contracts and strict native parity, independent of GPU access."""
import os
import subprocess
from pathlib import Path

import numpy as np
import pytest

Expand Down Expand Up @@ -358,27 +362,47 @@ def test_parsed_mma_rejects_wrong_operands():
native.lower_serialized_ir(ir, arch="gfx942")


@pytest.fixture(scope="module")
def tf32_recipe_replay_cli():
"""Use the launcher-supplied native VM shared by replay suites."""
executable = os.environ.get("ROCKE_REPLAY_CLI")
if not executable:
pytest.skip("Set ROCKE_REPLAY_CLI to the prebuilt native replay CLI")
path = Path(executable).resolve()
if not path.is_file():
pytest.skip(f"TF32 native replay CLI not found: {path}")
return path


@pytest.mark.parametrize("m", [16, 32])
@pytest.mark.parametrize("mode", PREPARATIONS)
@pytest.mark.skip(
reason=(
"Temporarily disabled (#12612): native recipe replay attempts a source "
"build from installed test artifacts"
)
)
def test_recipe_replay_preserves_ir(m, mode, monkeypatch):
def test_recipe_replay_preserves_ir(m, mode, tmp_path, tf32_recipe_replay_cli):
from rocke.portable_ir.src.recording_builder import record_kernel
from rocke.portable_ir.src import online, recipe_bundle
from rocke.portable_ir.src import recipe_bundle

spec = Tf32MmaProbeSpec(m, mode)
recorded, recipe = record_kernel(lambda: build_tf32_mma_probe(spec))
assert serialize(recorded) == serialize(build_tf32_mma_probe(spec))
path = tmp_path / "recipe.cbor"
path.write_bytes(recipe_bundle.cbor_encode(recipe))
for flavor in ("llvm20", "llvm22", "llvm23"):
monkeypatch.setenv("ROCKE_LLVM_FLAVOR", flavor)
replayed, _ = online.recipe_cbor_to_llvm(
recipe_bundle.cbor_encode(recipe), arch="gfx942"
replayed = subprocess.run(
[
str(tf32_recipe_replay_cli),
"--recipe",
str(path),
"--cbor",
"--arch",
"gfx942",
"--flavor",
flavor,
],
capture_output=True,
text=True,
check=True,
timeout=30,
)
assert replayed == _lower_kernel_to_llvm_python(
assert replayed.stdout == _lower_kernel_to_llvm_python(
recorded, arch="gfx942", llvm_flavor=flavor
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
import importlib.util
import os
import pytest
from rocke.runtime.hip_module import get_device_arch
from rocke.examples.gfx942.tf32_numerics import run


@pytest.mark.skip(
reason=(
"Temporarily disabled (#12612): both-backend test requires rocke_engine, "
"absent from installed test artifacts"
)
)
def test_gfx942_tf32_numeric(tmp_path):
arch = get_device_arch()
if not arch or arch.split(":")[0] != "gfx942":
if os.getenv("ROCKE_REQUIRE_GFX942") == "1":
pytest.fail(f"Required gfx942 device absent: {arch}")
pytest.skip("requires gfx942")
result = run(tmp_path, backend="both")
# The installed wheel has no pybind extension. Keep numerical coverage in
# that layout and demand native parity whenever the binding is supplied.
backend = "python" if importlib.util.find_spec("rocke_engine") is None else "both"
result = run(tmp_path, backend=backend)
assert result["status"] == "pass"
assert len(result["results"]) == 24
engines = {"python"} if backend == "python" else {"python", "cpp"}
assert {row["engine"] for row in result["results"]} == engines
assert len(result["results"]) == 12 * len(engines)
Loading