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
274 lines
9.0 KiB
Python
274 lines
9.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
This is a generic test runner that can test multiple components.
|
|
This works on components in rocm-libraries/rocm-systems which use test_categories.yml for test categorization.
|
|
|
|
Environment variables used:
|
|
TEST_COMPONENT: Job name of the component to test (e.g., "miopen", "rocrand", "hiprand")
|
|
This is automatically set by the GitHub Actions workflow from the job_name field.
|
|
The script maps these job names to actual test directory names (e.g., "miopen" -> "MIOpen")
|
|
Defaults to "miopen" if not set.
|
|
TEST_TYPE: Test category to run - one of "quick", "standard", "comprehensive", or "full".
|
|
Defaults to "quick". Invalid values fall back to "quick" with an error message.
|
|
AMDGPU_FAMILIES: Parsed to extract GPU architecture (e.g., "gfx1151")
|
|
|
|
The script discovers GPU-specific labels via ctest --print-labels and runs the appropriate tests for the current GPU architecture.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import re
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
THEROCK_BIN_DIR = os.getenv("THEROCK_BIN_DIR")
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
THEROCK_DIR = Path(
|
|
os.environ.get("THEROCK_DIR") or SCRIPT_DIR.parent.parent.parent
|
|
).resolve()
|
|
VALID_TEST_CATEGORIES = {"quick", "standard", "comprehensive", "full"}
|
|
TEST_TYPE = os.getenv("TEST_TYPE", "quick")
|
|
AMDGPU_FAMILIES = os.getenv("AMDGPU_FAMILIES")
|
|
|
|
# Map job names to actual test directory names
|
|
# The job names come from TEST_COMPONENT env var (set by GitHub Actions workflow)
|
|
# and need to be mapped to the actual directory names in THEROCK_BIN_DIR
|
|
COMPONENT_DIR_MAPPING = {
|
|
"miopen": "MIOpen",
|
|
"rocblas": "rocblas",
|
|
"hipblas": "hipblas",
|
|
"rocrand": "rocRAND",
|
|
"hiprand": "hipRAND",
|
|
"rocthrust": "rocthrust",
|
|
"rocprim": "rocprim",
|
|
"rocwmma": "rocwmma",
|
|
"hipcub": "hipcub",
|
|
"hipdnn": "hipdnn",
|
|
"hipdnn-samples": "hipdnn_samples",
|
|
"miopen_plugin": "miopen_legacy_plugin",
|
|
"hiptensor": "hiptensor",
|
|
# Add more mappings as needed
|
|
}
|
|
|
|
# Get the test component from environment (required - no default)
|
|
test_component_job_name = os.getenv("TEST_COMPONENT")
|
|
if not test_component_job_name:
|
|
print(
|
|
"ERROR: TEST_COMPONENT environment variable is required but not set.",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
TEST_COMPONENT = COMPONENT_DIR_MAPPING.get(
|
|
test_component_job_name, test_component_job_name
|
|
)
|
|
|
|
# GTest sharding
|
|
SHARD_INDEX = os.getenv("SHARD_INDEX", 1)
|
|
TOTAL_SHARDS = os.getenv("TOTAL_SHARDS", 1)
|
|
|
|
# CTest parallel jobs (use fewer in less capable platforms)
|
|
ctest_parallel_count = 8
|
|
if AMDGPU_FAMILIES and "gfx1152" in AMDGPU_FAMILIES:
|
|
ctest_parallel_count = 4
|
|
elif AMDGPU_FAMILIES and "gfx1153" in AMDGPU_FAMILIES:
|
|
ctest_parallel_count = 4
|
|
|
|
# CTest per-test timeout (default 2 hours, in seconds)
|
|
# There should be a timeout set from component level, but this can be used as an override
|
|
ctest_timeout_seconds = 7200
|
|
|
|
environ_vars = os.environ.copy()
|
|
# Set the GTEST env vars for Gtest based tests
|
|
# Set ROCM_PATH for tests that rely on it
|
|
environ_vars["GTEST_SHARD_INDEX"] = str(int(SHARD_INDEX) - 1)
|
|
environ_vars["GTEST_TOTAL_SHARDS"] = str(TOTAL_SHARDS)
|
|
ROCM_PATH = Path(THEROCK_BIN_DIR).resolve().parent
|
|
environ_vars["ROCM_PATH"] = str(ROCM_PATH)
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
def find_matching_gpu_arch(gpu_arch: str, available_gpu_archs: set[str]) -> str | None:
|
|
"""
|
|
Find the most specific GPU architecture in the set that matches the given GPU.
|
|
|
|
Tries in order from most specific to least specific:
|
|
# Example:
|
|
# find_matching_gpu_arch('gfx1151', {'gfx1151', 'gfx115X', 'gfx11X'}) gives 'gfx1151'
|
|
# find_matching_gpu_arch('gfx1151', {'gfx1150', 'gfx94X', 'gfx11X'}) gives 'gfx11X'
|
|
- Wildcard matches (gfx115X, gfx11X, etc.)
|
|
|
|
Returns the matching architecture string or None if no match found.
|
|
"""
|
|
if gpu_arch in available_gpu_archs:
|
|
return gpu_arch
|
|
|
|
# Start matching from the end (gfx115X) and go back till the 5th character (gfx11X)
|
|
# Return the top matching pattern
|
|
for i in range(len(gpu_arch) - 1, 4, -1):
|
|
pattern = gpu_arch[:i] + "X"
|
|
if pattern in available_gpu_archs:
|
|
return pattern
|
|
|
|
return None
|
|
|
|
|
|
def get_available_gpu_suite_tests():
|
|
"""
|
|
Get all available GPU architecture labels from ctest --print-labels.
|
|
|
|
Parses labels of the form ex_gpu_{gpu_arch} (e.g. ex_gpu_gfx110X, ex_gpu_gfx950).
|
|
Returns a set of gpu_arch strings (e.g., 'gfx110X', 'gfx115X', 'gfx950').
|
|
"""
|
|
test_dir = Path(THEROCK_BIN_DIR) / TEST_COMPONENT
|
|
if not test_dir.exists() or not test_dir.is_dir():
|
|
print(f"Error: Test directory does not exist: {test_dir}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
try:
|
|
# Ensure the component has at least one test
|
|
list_result = subprocess.run(
|
|
["ctest", "-N", "--test-dir", str(test_dir)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
total_tests = sum(
|
|
1
|
|
for line in list_result.stdout.splitlines()
|
|
if re.search(r"Test\s+#\d+:", line)
|
|
)
|
|
if total_tests == 0:
|
|
print(
|
|
f"Error: No tests found in {test_dir}. Cannot run test suite.",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
result = subprocess.run(
|
|
["ctest", "--print-labels", "--test-dir", str(test_dir)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
gpu_archs = set()
|
|
prefix = "ex_gpu_"
|
|
for line in result.stdout.splitlines():
|
|
label = line.strip()
|
|
if label.startswith(prefix):
|
|
gpu_arch = label[len(prefix) :]
|
|
if gpu_arch.startswith("gfx"):
|
|
gpu_archs.add(gpu_arch)
|
|
|
|
return gpu_archs
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error running ctest --print-labels: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
except FileNotFoundError:
|
|
print(
|
|
"Error: ctest not found. Make sure CMake/CTest is installed.",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
def build_ctest_command(category, gpu_arch, available_gpu_archs):
|
|
"""
|
|
Build the appropriate ctest command based on the category and GPU architecture.
|
|
|
|
Returns a list of command arguments suitable for subprocess.run()
|
|
"""
|
|
cmd = ["ctest", "-L", category]
|
|
|
|
# Add common ctest parameters
|
|
cmd.extend(
|
|
[
|
|
"--output-on-failure",
|
|
"--parallel",
|
|
f"{ctest_parallel_count}",
|
|
"--timeout",
|
|
str(ctest_timeout_seconds),
|
|
"--test-dir",
|
|
f"{THEROCK_BIN_DIR}/{TEST_COMPONENT}",
|
|
"-V",
|
|
"--tests-information",
|
|
f"{SHARD_INDEX},,{TOTAL_SHARDS}",
|
|
]
|
|
)
|
|
|
|
if gpu_arch.lower() in ["generic", "none", ""]:
|
|
cmd.extend(["-LE", "ex_gpu"])
|
|
return cmd
|
|
|
|
matching_arch = find_matching_gpu_arch(gpu_arch, available_gpu_archs)
|
|
|
|
if matching_arch:
|
|
gpu_label = f"ex_gpu_{matching_arch}"
|
|
cmd.extend(["-L", gpu_label])
|
|
print(f"# Using GPU suite label: {gpu_label}")
|
|
else:
|
|
cmd.extend(["-LE", "ex_gpu"])
|
|
print(f"# No GPU suite found for {gpu_arch}, excluding all ex_gpu tests")
|
|
|
|
return cmd
|
|
|
|
|
|
def main():
|
|
category = TEST_TYPE.lower() if TEST_TYPE else "quick"
|
|
if category not in VALID_TEST_CATEGORIES:
|
|
print(
|
|
f"ERROR: Invalid TEST_TYPE '{TEST_TYPE}'. "
|
|
f"Must be one of: {', '.join(sorted(VALID_TEST_CATEGORIES))}. "
|
|
f"Falling back to 'quick'.",
|
|
file=sys.stderr,
|
|
)
|
|
category = "quick"
|
|
|
|
gpu_arch = ""
|
|
if AMDGPU_FAMILIES:
|
|
match = re.search(r"gfx[0-9a-zA-Z]+", AMDGPU_FAMILIES)
|
|
if match:
|
|
gpu_arch = match.group(0)
|
|
else:
|
|
print(
|
|
f"# Warning: Could not extract GPU architecture from AMDGPU_FAMILIES='{AMDGPU_FAMILIES}', using default '{gpu_arch}'"
|
|
)
|
|
|
|
print(
|
|
f"# TEST_COMPONENT: {test_component_job_name} -> Test Directory: {TEST_COMPONENT}"
|
|
)
|
|
print(f"# TEST_TYPE: {TEST_TYPE} -> Category: {category}")
|
|
print(f"# AMDGPU_FAMILIES: {AMDGPU_FAMILIES} -> GPU Architecture: {gpu_arch}")
|
|
print()
|
|
|
|
print("# Discovering available GPU suite tests...")
|
|
available_gpu_archs = get_available_gpu_suite_tests()
|
|
|
|
if available_gpu_archs:
|
|
print(f"# Found {len(available_gpu_archs)} GPU suite test(s)")
|
|
print(f"# Available GPU architectures: {sorted(available_gpu_archs)}")
|
|
else:
|
|
print("# Warning: No GPU specific test suites available")
|
|
print()
|
|
|
|
cmd = build_ctest_command(category, gpu_arch, available_gpu_archs)
|
|
|
|
print(f"# Running: {' '.join(cmd)}")
|
|
print()
|
|
|
|
try:
|
|
logging.info(f"++ Exec [{THEROCK_DIR}]$ {shlex.join(cmd)}")
|
|
result = subprocess.run(cmd, cwd=THEROCK_DIR, env=environ_vars, check=False)
|
|
return result.returncode
|
|
except Exception as e:
|
|
print(f"Error running ctest: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|