3b875cc0ee
* Initial work in progress for compute CI workflow * Update run-ci.py script location, enable test creation * Add new lines to files * Add coverage file argument to run-ci.py * Remove run-ci.py script usage from rocprofiler-compute-continuous-integration.yml workflow * Add --break-system-packages parameter * Add --ignore-installed to pip install * Checkout specific branch until amdclang issue fixed in develop * Add missing slash to path for cxx compiler * Remove specific branch from checkout action * Use run-ci.py in rocprofiler-compute-continuous-integration.yml * Update install python requirements step * Fix typo in build-name * Update run-ci.py to have toggle for code coverage * Apply ruff formatting * Ruff again * Exclude live attach detach and roofline tests in CI * Add ctest args * Revert run-ci.py changes * Try new run-ci-2.py * Update type of pytest-numprocs argument * Try casting arg to str * Fix typo in arg reference * upgrade pip before running python installs * Use jammy instead of noble for CI * Remove python nproc arg from run-ci-2.py * Switch to MI325 runners for CI * Fix spacing issue * Rename run-ci.py to run-code-coverage.py, add new run-ci.py * Update to ROCm version 7.1.0 to debug sdk issues * Testing out tarball install again * Update regex on tarball version * Update tarball regex on compute * ruff formatting * Revert change to systems CI file * Switch back to rocm-dev install * ruff formatting again * Add ld_lib_path for rocm_sysdeps * Remove excluded tests temporarily * Add back excluded tests, add timeout for test step * Address PR feedback * Add git safe directory lines * Revert dependencies change to debug new failures * Exclude roofline again, rework dependencies * Add in hip-runtime-amd dependency * Install hip dev package * Add TEST_FROM_INSTALL cmake arg to compute CI workflow * Remove test_from_install for now * Enable roofline tests again
404 satır
12 KiB
Python
404 satır
12 KiB
Python
#!/usr/bin/env python3
|
|
##############################################################################
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
##############################################################################
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
|
|
def detect_repo_structure():
|
|
"""Detect if in monorepo or standalone structure"""
|
|
cwd = Path.cwd()
|
|
|
|
if "projects/rocprofiler-compute" in str(cwd):
|
|
parts = cwd.parts
|
|
idx = parts.index("rocprofiler-compute")
|
|
if idx > 0 and parts[idx - 1] == "projects":
|
|
monorepo_root = Path(*parts[: idx - 1])
|
|
project_root = monorepo_root / "projects" / "rocprofiler-compute"
|
|
return True, monorepo_root, project_root
|
|
|
|
if (cwd / "CMakeLists.txt").exists():
|
|
with open(cwd / "CMakeLists.txt") as f:
|
|
content = f.read()
|
|
if (
|
|
"project(rocprofiler-compute" in content
|
|
or "project(\n rocprofiler-compute" in content
|
|
):
|
|
return False, None, cwd
|
|
|
|
return False, None, cwd
|
|
|
|
|
|
def generate_ctest_dashboard_script(args, source_dir, binary_dir):
|
|
"""
|
|
Generate a complete CTest dashboard script that handles:
|
|
- Configuration
|
|
- Build
|
|
- Test
|
|
- Coverage
|
|
- Submit to CDash
|
|
"""
|
|
|
|
cache_entries = [
|
|
"CMAKE_BUILD_TYPE:STRING=Release",
|
|
f"CMAKE_PREFIX_PATH:PATH={os.environ.get('ROCM_PATH', '/opt/rocm')}",
|
|
"ENABLE_TESTS:BOOL=ON",
|
|
"INSTALL_TESTS:BOOL=ON",
|
|
"ENABLE_COVERAGE:BOOL=ON",
|
|
f"PYTEST_NUMPROCS:STRING={args.pytest_numprocs}",
|
|
]
|
|
|
|
test_args = ""
|
|
if args.ctest_args:
|
|
test_args = " ".join(args.ctest_args)
|
|
|
|
# ruff: noqa
|
|
script_content = f"""
|
|
cmake_minimum_required(VERSION 3.19)
|
|
|
|
##############################################################################
|
|
# CTest Dashboard Script for rocprofiler-compute
|
|
# Auto-generated by run-ci.py
|
|
##############################################################################
|
|
|
|
# Dashboard configuration
|
|
set(CTEST_PROJECT_NAME "{args.project_name}")
|
|
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
|
|
set(CTEST_DROP_SITE_CDASH TRUE)
|
|
|
|
# CDash submission settings
|
|
if(CMAKE_VERSION VERSION_GREATER 3.14)
|
|
set(CTEST_SUBMIT_URL "{args.submit_url}")
|
|
else()
|
|
set(CTEST_DROP_METHOD "https")
|
|
set(CTEST_DROP_SITE "{args.cdash_host}")
|
|
set(CTEST_DROP_LOCATION "{args.submit_path}")
|
|
endif()
|
|
|
|
# Build identification
|
|
set(CTEST_SITE "{args.site}")
|
|
set(CTEST_BUILD_NAME "{args.build_name}")
|
|
set(CTEST_SOURCE_DIRECTORY "{source_dir}")
|
|
set(CTEST_BINARY_DIRECTORY "{binary_dir}")
|
|
|
|
# Build config
|
|
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
|
|
set(CTEST_BUILD_CONFIGURATION "Release")
|
|
|
|
# Config CMake command with all required options
|
|
set(CTEST_CONFIGURE_COMMAND "cmake -B ${{CTEST_BINARY_DIRECTORY}} ${{CTEST_SOURCE_DIRECTORY}} -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH={os.environ.get("ROCM_PATH", "/opt/rocm")} -DENABLE_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_COVERAGE=ON -DPYTEST_NUMPROCS={args.pytest_numprocs}")
|
|
|
|
message(STATUS "CMake configure command: ${{CTEST_CONFIGURE_COMMAND}}")
|
|
|
|
message(STATUS "Starting {args.mode} dashboard...")
|
|
ctest_start({args.mode})
|
|
|
|
# Config step
|
|
message(STATUS "Configuring project...")
|
|
ctest_configure(
|
|
RETURN_VALUE configure_result
|
|
CAPTURE_CMAKE_ERROR configure_error
|
|
)
|
|
|
|
if(configure_result OR configure_error)
|
|
message(WARNING "Configuration had issues but continuing...")
|
|
endif()
|
|
|
|
# Build step
|
|
message(STATUS "Building project...")
|
|
set(CTEST_BUILD_FLAGS "-j{args.build_jobs}")
|
|
ctest_build(
|
|
TARGET {"install" if args.install else "all"}
|
|
RETURN_VALUE build_result
|
|
CAPTURE_CMAKE_ERROR build_error
|
|
)
|
|
|
|
if(build_result OR build_error)
|
|
message(WARNING "Build had issues but continuing...")
|
|
endif()
|
|
|
|
# Test step
|
|
message(STATUS "Running tests...")
|
|
ctest_test(
|
|
{test_args}
|
|
PARALLEL_LEVEL 1
|
|
RETURN_VALUE test_result
|
|
CAPTURE_CMAKE_ERROR test_error
|
|
)
|
|
|
|
if(test_result OR test_error)
|
|
message(WARNING "Some tests failed but continuing with coverage and upload...")
|
|
endif()
|
|
|
|
# Coverage step (if coverage file exists)
|
|
set(COVERAGE_FILE "${{CTEST_BINARY_DIRECTORY}}/coverage.xml")
|
|
if(EXISTS "${{COVERAGE_FILE}}")
|
|
message(STATUS "Processing coverage data...")
|
|
|
|
file(MAKE_DIRECTORY "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo")
|
|
file(COPY "${{COVERAGE_FILE}}"
|
|
DESTINATION "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo/")
|
|
|
|
ctest_coverage(
|
|
RETURN_VALUE coverage_result
|
|
CAPTURE_CMAKE_ERROR coverage_error
|
|
)
|
|
|
|
if(coverage_result OR coverage_error)
|
|
message(WARNING "Coverage processing had issues but continuing...")
|
|
endif()
|
|
else()
|
|
message(STATUS "No coverage file found at ${{COVERAGE_FILE}}")
|
|
message(STATUS "Skipping coverage step")
|
|
endif()
|
|
|
|
message(STATUS "Submitting to CDash...")
|
|
ctest_submit(
|
|
RETRY_COUNT 3
|
|
RETRY_DELAY 5
|
|
RETURN_VALUE submit_result
|
|
CAPTURE_CMAKE_ERROR submit_error
|
|
)
|
|
|
|
if(submit_result OR submit_error)
|
|
message(WARNING "CDash submission encountered issues")
|
|
message(STATUS "Results available locally in: ${{CTEST_BINARY_DIRECTORY}}/Testing/")
|
|
else()
|
|
message(STATUS "Successfully submitted to CDash!")
|
|
message(STATUS "View at: {args.submit_url.replace("/submit.php?project=", "/index.php?project=")}")
|
|
message(STATUS "Build name: {args.build_name}")
|
|
endif()
|
|
|
|
message(STATUS "")
|
|
message(STATUS "========================================")
|
|
message(STATUS "Dashboard Summary")
|
|
message(STATUS "========================================")
|
|
if(test_result)
|
|
message(STATUS "Tests: FAILED (some tests failed or timed out)")
|
|
else()
|
|
message(STATUS "Tests: PASSED")
|
|
endif()
|
|
if(submit_result OR submit_error)
|
|
message(STATUS "CDash Upload: FAILED")
|
|
else()
|
|
message(STATUS "CDash Upload: SUCCESS")
|
|
endif()
|
|
message(STATUS "========================================")
|
|
|
|
# For nightly/continuous, don't fail on test failures
|
|
# Only warn in Experimental mode
|
|
if("{args.mode}" STREQUAL "Experimental" AND test_result)
|
|
message(WARNING "Tests failed in Experimental mode")
|
|
endif()
|
|
"""
|
|
|
|
return script_content
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="CI script for rocprofiler-compute: build, test, and upload to CDash"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--build-name",
|
|
"--name",
|
|
dest="build_name",
|
|
required=True,
|
|
help="Build name for CDash",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--project-name",
|
|
default="rocprofiler-compute",
|
|
help="CDash project name",
|
|
)
|
|
parser.add_argument(
|
|
"--submit-url",
|
|
default="https://my.cdash.org/submit.php?project=rocprofiler-compute",
|
|
help="CDash submission URL",
|
|
)
|
|
parser.add_argument(
|
|
"--cdash-host",
|
|
default="my.cdash.org",
|
|
help="CDash host (for older CMake)",
|
|
)
|
|
parser.add_argument(
|
|
"--submit-path",
|
|
default="/submit.php?project=rocprofiler-compute",
|
|
help="CDash submission path (for older CMake)",
|
|
)
|
|
parser.add_argument(
|
|
"--site",
|
|
default=None,
|
|
help="Site name for CDash (auto-detected if not provided)",
|
|
)
|
|
parser.add_argument(
|
|
"--source-dir",
|
|
"-S",
|
|
default=None,
|
|
help="Source directory path (auto-detected if not provided)",
|
|
)
|
|
parser.add_argument(
|
|
"--binary-dir",
|
|
"-B",
|
|
default=None,
|
|
help="Binary directory path (defaults to source-dir/build)",
|
|
)
|
|
parser.add_argument(
|
|
"--mode",
|
|
default="Experimental",
|
|
choices=["Experimental", "Nightly", "Continuous"],
|
|
help="CTest dashboard mode",
|
|
)
|
|
parser.add_argument(
|
|
"--build-jobs",
|
|
"-j",
|
|
type=int,
|
|
default=8,
|
|
help="Number of parallel build jobs",
|
|
)
|
|
parser.add_argument(
|
|
"--install",
|
|
action="store_true",
|
|
help="Build install target instead of all target",
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Generate dashboard script but don't execute",
|
|
)
|
|
parser.add_argument(
|
|
"--pytest-numprocs",
|
|
type=int,
|
|
default=4,
|
|
help="Number of parallel processes for pytest",
|
|
)
|
|
|
|
args, unknown = parser.parse_known_args()
|
|
|
|
args.cmake_args = []
|
|
args.ctest_args = []
|
|
|
|
is_monorepo, monorepo_root, project_root = detect_repo_structure()
|
|
|
|
if not args.source_dir:
|
|
args.source_dir = str(project_root)
|
|
|
|
if not args.binary_dir:
|
|
args.binary_dir = os.path.join(args.source_dir, "build")
|
|
|
|
if not args.site:
|
|
if is_monorepo:
|
|
args.site = f"Monorepo-{os.uname().nodename}"
|
|
else:
|
|
args.site = os.uname().nodename
|
|
|
|
source_dir = Path(args.source_dir).absolute()
|
|
binary_dir = Path(args.binary_dir).absolute()
|
|
|
|
print("=" * 80)
|
|
print("rocprofiler-compute CI Dashboard")
|
|
print("=" * 80)
|
|
print(f"Repository type: {'Monorepo' if is_monorepo else 'Standalone'}")
|
|
print(f"Source directory: {source_dir}")
|
|
print(f"Binary directory: {binary_dir}")
|
|
print(f"Build name: {args.build_name}")
|
|
print(f"Dashboard mode: {args.mode}")
|
|
print(f"CDash project: {args.project_name}")
|
|
print(f"Site: {args.site}")
|
|
print("=" * 80)
|
|
|
|
script_content = generate_ctest_dashboard_script(args, source_dir, binary_dir)
|
|
|
|
if args.dry_run:
|
|
print("\nGenerated CTest Dashboard Script:")
|
|
print("=" * 80)
|
|
print(script_content)
|
|
print("=" * 80)
|
|
return 0
|
|
|
|
binary_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".cmake", delete=False, dir=binary_dir
|
|
) as f:
|
|
f.write(script_content)
|
|
script_path = f.name
|
|
|
|
print(f"\nDashboard script: {script_path}")
|
|
print("=" * 80)
|
|
|
|
try:
|
|
cmd = ["ctest", "-S", script_path, "-V"]
|
|
print(f"Running: {' '.join(cmd)}")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
process = subprocess.Popen(
|
|
cmd,
|
|
cwd=source_dir,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
universal_newlines=True,
|
|
)
|
|
|
|
for line in process.stdout:
|
|
print(line, end="")
|
|
|
|
returncode = process.wait()
|
|
|
|
print()
|
|
print("=" * 80)
|
|
if returncode == 0:
|
|
print("✅ Dashboard completed successfully!")
|
|
else:
|
|
print(f"⚠️ Dashboard completed with return code: {returncode}")
|
|
print("=" * 80)
|
|
|
|
return returncode
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ Error executing dashboard script: {e}", file=sys.stderr)
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
return 1
|
|
finally:
|
|
try:
|
|
os.unlink(script_path)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|