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
260 lines
8.4 KiB
Python
260 lines
8.4 KiB
Python
# Copyright Advanced Micro Devices, Inc.
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
Shared base class for benchmark and functional tests.
|
|
|
|
Both BenchmarkBase and FunctionalBase inherit from ExtendedTestBase.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any, Dict, IO, List, Optional
|
|
|
|
# Add build_tools/github_actions to path for github_actions_api
|
|
sys.path.insert(
|
|
0, str(Path(__file__).resolve().parents[3] / "build_tools" / "github_actions")
|
|
)
|
|
|
|
from .logger import log
|
|
from .exceptions import TestExecutionError
|
|
from .extended_test_client import ExtendedTestClient
|
|
|
|
from github_actions_api import (
|
|
gha_append_step_summary,
|
|
)
|
|
|
|
|
|
class ExtendedTestBase:
|
|
"""Base class providing shared infrastructure for extended tests."""
|
|
|
|
def __init__(self, test_name: str, display_name: str = None):
|
|
"""Initialize common extended test infrastructure.
|
|
|
|
Args:
|
|
test_name: Internal test name (e.g., 'rocfft', 'miopen_driver_conv')
|
|
display_name: Display name for reports, defaults to test_name
|
|
"""
|
|
self.test_name = test_name
|
|
self.display_name = display_name or test_name
|
|
|
|
# Environment variables
|
|
self.therock_bin_dir = os.getenv("THEROCK_BIN_DIR")
|
|
self.artifact_run_id = os.getenv("ARTIFACT_RUN_ID")
|
|
self.amdgpu_families = os.getenv("AMDGPU_FAMILIES")
|
|
self.therock_dir = Path(__file__).resolve().parents[3]
|
|
self.rocm_path = (
|
|
Path(self.therock_bin_dir).resolve().parent
|
|
if self.therock_bin_dir
|
|
else None
|
|
)
|
|
|
|
# Initialize test client with auto-detection
|
|
self.client = ExtendedTestClient(auto_detect=True)
|
|
self.client.print_system_summary()
|
|
|
|
def load_config(self, config_filename: str) -> Dict[str, Any]:
|
|
"""Load test configuration from JSON file in configs/ directory.
|
|
|
|
Expects self.script_dir to be set by the child class.
|
|
Config file is resolved as: <script_dir>/../configs/<config_filename>
|
|
"""
|
|
config_file = self.script_dir.parent / "configs" / config_filename
|
|
|
|
try:
|
|
with open(config_file, "r") as f:
|
|
return json.load(f)
|
|
except FileNotFoundError:
|
|
raise TestExecutionError(
|
|
f"Configuration file not found: {config_file}\n"
|
|
f"Ensure {config_filename} exists in configs/ directory"
|
|
)
|
|
except json.JSONDecodeError as e:
|
|
raise TestExecutionError(
|
|
f"Invalid JSON in configuration file: {e}\n"
|
|
f"Check JSON syntax in {config_filename}"
|
|
)
|
|
|
|
def execute_command(
|
|
self,
|
|
cmd: List[str],
|
|
log_file_handle: Optional[IO] = None,
|
|
env: Optional[Dict[str, str]] = None,
|
|
cwd: Optional[str] = None,
|
|
) -> int:
|
|
"""Execute a command, stream output to log, and optionally write to a file.
|
|
|
|
Args:
|
|
cmd: Command list to execute.
|
|
log_file_handle: Optional file handle to write output to (used by benchmarks).
|
|
env: Optional environment variables to merge with current environment.
|
|
cwd: Working directory for the command. Defaults to self.therock_dir.
|
|
|
|
Returns:
|
|
Exit code from the command.
|
|
"""
|
|
run_cwd = cwd or str(self.therock_dir)
|
|
log.info(f"++ Exec [{run_cwd}]$ {shlex.join(cmd)}")
|
|
if log_file_handle:
|
|
log_file_handle.write(f"{shlex.join(cmd)}\n")
|
|
|
|
# Merge custom env with current environment
|
|
process_env = os.environ.copy()
|
|
if env:
|
|
process_env.update(env)
|
|
|
|
process = subprocess.Popen(
|
|
cmd,
|
|
cwd=run_cwd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
env=process_env,
|
|
)
|
|
|
|
for line in process.stdout:
|
|
log.info(line.strip())
|
|
if log_file_handle:
|
|
log_file_handle.write(f"{line}")
|
|
|
|
process.wait()
|
|
return process.returncode
|
|
|
|
def create_test_result(
|
|
self,
|
|
test_name: str,
|
|
subtest_name: str,
|
|
status: str,
|
|
**kwargs,
|
|
) -> Dict[str, Any]:
|
|
"""Create a standardized test result dictionary.
|
|
|
|
Builds the base result structure used by extended tests.
|
|
|
|
Args:
|
|
test_name: Test name (e.g., 'rocfft')
|
|
subtest_name: Specific test/suite identifier
|
|
status: 'PASS', 'FAIL', 'ERROR', or 'SKIP'
|
|
**kwargs: Additional fields (e.g., score/unit/flag/batch_size/ngpu for benchmarks,
|
|
suite/command for functional tests).
|
|
"""
|
|
python_version = (
|
|
f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
f".{sys.version_info.micro}"
|
|
)
|
|
|
|
# Build test_config with base fields + all kwargs
|
|
test_config = {
|
|
"test_name": test_name,
|
|
"sub_test_name": subtest_name,
|
|
"python_version": python_version,
|
|
"environment_dependencies": [],
|
|
**kwargs,
|
|
}
|
|
|
|
return {
|
|
"test_name": test_name,
|
|
"subtest": subtest_name,
|
|
"status": status,
|
|
"test_config": test_config,
|
|
**kwargs,
|
|
}
|
|
|
|
def calculate_statistics(
|
|
self,
|
|
test_results: List[Dict[str, Any]],
|
|
) -> Dict[str, Any]:
|
|
"""Calculate pass/fail statistics from test results and return a dictionary with the counts.
|
|
|
|
Args:
|
|
test_results: List of test result dicts with 'status' key.
|
|
"""
|
|
counts = {
|
|
"passed": sum(1 for r in test_results if r.get("status") == "PASS"),
|
|
"failed": sum(1 for r in test_results if r.get("status") == "FAIL"),
|
|
"error": sum(1 for r in test_results if r.get("status") == "ERROR"),
|
|
"skipped": sum(1 for r in test_results if r.get("status") == "SKIP"),
|
|
}
|
|
|
|
counts["total"] = len(test_results)
|
|
counts["overall_status"] = (
|
|
"PASS" if (counts["failed"] + counts["error"]) == 0 else "FAIL"
|
|
)
|
|
|
|
return counts
|
|
|
|
def upload_results(
|
|
self,
|
|
test_results: List[Dict[str, Any]],
|
|
stats: Dict[str, Any],
|
|
test_type: str,
|
|
output_dir: str,
|
|
extra_metadata: Optional[Dict[str, Any]] = None,
|
|
) -> bool:
|
|
"""Upload test results to API and save locally.
|
|
|
|
Args:
|
|
test_results: List of test result dictionaries.
|
|
stats: Statistics from calculate_statistics().
|
|
test_type: 'benchmark' or 'functional'.
|
|
output_dir: Directory to save local results.
|
|
extra_metadata: Optional additional metadata for upload.
|
|
"""
|
|
metadata = {
|
|
"artifact_run_id": self.artifact_run_id,
|
|
"amdgpu_families": self.amdgpu_families,
|
|
"test_name": self.test_name,
|
|
}
|
|
if extra_metadata:
|
|
metadata.update(extra_metadata)
|
|
|
|
log.info(f"Uploading {test_type.title()} Test Results to API")
|
|
success = self.client.upload_results(
|
|
test_name=f"{self.test_name}_{test_type}",
|
|
test_results=test_results,
|
|
test_status=stats["overall_status"],
|
|
test_metadata=metadata,
|
|
save_local=True,
|
|
output_dir=output_dir,
|
|
)
|
|
|
|
if success:
|
|
log.info("Results uploaded successfully")
|
|
else:
|
|
log.error(
|
|
f"API upload failed for '{self.test_name}' {test_type} results. "
|
|
f"Results were saved locally to '{output_dir}'. "
|
|
)
|
|
|
|
return success
|
|
|
|
def get_rocm_env(self, additional_paths: List[Path] = None) -> Dict[str, str]:
|
|
"""Get environment with LD_LIBRARY_PATH set for ROCm libraries.
|
|
|
|
Args:
|
|
additional_paths: Additional library paths to include
|
|
|
|
Returns:
|
|
Environment dictionary with LD_LIBRARY_PATH configured
|
|
"""
|
|
env = os.environ.copy()
|
|
rocm_lib = self.rocm_path / "lib"
|
|
|
|
# Build list of library paths
|
|
lib_paths = [str(rocm_lib)]
|
|
if additional_paths:
|
|
lib_paths.extend(str(p) for p in additional_paths)
|
|
|
|
# Append existing LD_LIBRARY_PATH if present
|
|
existing = env.get("LD_LIBRARY_PATH", "")
|
|
if existing:
|
|
lib_paths.append(existing)
|
|
|
|
env["LD_LIBRARY_PATH"] = ":".join(lib_paths)
|
|
return env
|