[rocprof-compute] Automate ctest coverage and test cases on runners with CDash (#1481)
* Add nightly coverage workflow * ruff formatting * temp workflow testing * restore workflow file * add workflow condition * update workflow file * update workflow file * fix typo in run-ci.py * edit run-ci.py * add python deps install * add python deps install * add python deps install * add python deps install * check if enable coverage is on when using workflow * remove github CI breakdown and fix enable coverage * set cache variables must be set before dashboard starts * Update run-ci.py * Update run-ci.py to fix ctest cache * Update rocprofiler-compute-code-coverage.yml to install tests * Update rocprofiler-compute-code-coverage.yml * Restore workflow file * Update run-ci.py * Simplify workflow build command * Update run-ci.py to build tests * edited run-ci script * edit ctest configure commands * edit ctest configure commands to be on one line * edit ctest configure command to include path to amdclang++ * update clang check in tests/cmakelists.txt * update rocm * update rocm * update rocm version 7.0.2 * update tests/CMakeLists.txt * use tarball instead for rocm install * apt install rocm-dev instead for 7.0.0 release * workflow tweaks * update to use new 'tools' dir * install rocm-dev * add CMAKE_CXX_COMPILER as clang * update tests/cmakelists.txt * update cdasg site and build names * remove run automatically on pull requests * ruff format * increased timeouts for tests * add back reruns for workflow testing * fix typo * rename workflow "nightly" -> "code" * added tracks to keep track of gpu (325 vs 355) * remove test_db_connector.py * revert build names and tracking * update workflow pushes * CMake format * changed parallel level back to 1
This commit is contained in:
committed by
GitHub
parent
75ad45d5f1
commit
d49e2e35fd
@@ -1,89 +0,0 @@
|
||||
name: rocprofiler-compute CDash Coverage Upload
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
paths:
|
||||
- 'projects/rocprofiler-compute/coverage/Coverage.xml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
coverage_file:
|
||||
description: 'Path to coverage XML file'
|
||||
required: false
|
||||
default: 'projects/rocprofiler-compute/coverage/Coverage.xml'
|
||||
|
||||
concurrency:
|
||||
group: rocprofiler-compute-cdash-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
upload-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
name: Upload Coverage to CDash
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: projects/rocprofiler-compute
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Check Coverage File Exists
|
||||
working-directory: projects/rocprofiler-compute
|
||||
run: |
|
||||
COVERAGE_FILE="${{ github.event.inputs.coverage_file || 'coverage/Coverage.xml' }}"
|
||||
if [[ "$COVERAGE_FILE" == projects/rocprofiler-compute/* ]]; then
|
||||
COVERAGE_FILE="${COVERAGE_FILE#projects/rocprofiler-compute/}"
|
||||
fi
|
||||
|
||||
if [ ! -f "$COVERAGE_FILE" ]; then
|
||||
echo "ERROR: Coverage file not found at $COVERAGE_FILE!"
|
||||
echo "Please run manual coverage generation"
|
||||
echo "Use: cd projects/rocprofiler-compute && ./utils/update_coverage.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COVERAGE_INFO=$(python3 -c "
|
||||
import xml.etree.ElementTree as ET
|
||||
try:
|
||||
tree = ET.parse('$COVERAGE_FILE')
|
||||
root = tree.getroot()
|
||||
line_rate = float(root.get('line-rate', 0)) * 100
|
||||
print(f'{line_rate:.1f}%')
|
||||
except Exception as e:
|
||||
print(f'Error parsing coverage: {e}')
|
||||
exit(1)
|
||||
")
|
||||
|
||||
echo "Line Coverage: $COVERAGE_INFO"
|
||||
echo "COVERAGE_INFO=$COVERAGE_INFO" >> $GITHUB_ENV
|
||||
echo "COVERAGE_FILE=$COVERAGE_FILE" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload to CDash
|
||||
working-directory: projects/rocprofiler-compute
|
||||
run: |
|
||||
GIT_SHA_SHORT=$(git rev-parse --short HEAD)
|
||||
BRANCH_NAME=${GITHUB_REF#refs/heads/}
|
||||
|
||||
python3 utils/run-ci.py \
|
||||
--coverage-file "${{ env.COVERAGE_FILE }}" \
|
||||
--build-name "${BRANCH_NAME}-${GIT_SHA_SHORT}-$(date +%Y%m%d)" \
|
||||
--mode "Continuous" \
|
||||
--site "Monorepo-Upload" \
|
||||
--project-name "rocprofiler-compute" \
|
||||
--source-dir "." \
|
||||
--binary-dir "build"
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
echo "## CDash Upload Complete!" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Line Coverage**: ${{ env.COVERAGE_INFO }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Commit**: $(git rev-parse --short HEAD)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **CDash Project**: rocprofiler-compute" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Coverage File**: ${{ env.COVERAGE_FILE }}" >> $GITHUB_STEP_SUMMARY
|
||||
@@ -0,0 +1,157 @@
|
||||
name: rocprofiler-compute Code Coverage
|
||||
run-name: rocprofiler-compute-code-coverage
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
runner_matrix:
|
||||
description: 'Runner configuration'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
env:
|
||||
ROCM_PATH: "/opt/rocm"
|
||||
ROCM_VERSION: "7.0.2"
|
||||
|
||||
jobs:
|
||||
prepare_matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.generate_matrix.outputs.matrix }}
|
||||
|
||||
steps:
|
||||
- name: Generate matrix
|
||||
id: generate_matrix
|
||||
run: |
|
||||
MATRIX='[{"os-release":"22.04","gpu":"mi355","arch":"gfx950","runner":"linux-mi355-1gpu-ossci-rocm","code-name":"jammy"},{"os-release":"24.04","gpu":"mi355","arch":"gfx950","runner":"linux-mi355-1gpu-ossci-rocm","code-name":"noble"},{"os-release":"22.04","gpu":"mi325","arch":"gfx94X","runner":"linux-mi325-1gpu-ossci-rocm","code-name":"jammy"},{"os-release":"24.04","gpu":"mi325","arch":"gfx94X","runner":"linux-mi325-1gpu-ossci-rocm","code-name":"noble"}]'
|
||||
|
||||
if [ -n "${{ github.event.inputs.runner_matrix }}" ]; then
|
||||
MATRIX='${{ github.event.inputs.runner_matrix }}'
|
||||
fi
|
||||
|
||||
echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT
|
||||
|
||||
coverage:
|
||||
name: Coverage • ${{ matrix.system.gpu }} • Ubuntu ${{ matrix.system.os-release }}
|
||||
needs: prepare_matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
system: ${{ fromJSON(needs.prepare_matrix.outputs.matrix) }}
|
||||
runs-on: ${{ matrix.system.runner }}
|
||||
env:
|
||||
HIP_PLATFORM: "amd"
|
||||
OMPI_ALLOW_RUN_AS_ROOT: 1
|
||||
OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1
|
||||
permissions:
|
||||
packages: read
|
||||
container:
|
||||
image: ghcr.io/rocm/rocprofiler-ubuntu:${{ matrix.system.os-release }}-systems-ci-${{ matrix.system.arch }}
|
||||
options:
|
||||
--privileged
|
||||
--ipc host
|
||||
--group-add video
|
||||
--device /dev/kfd
|
||||
--device /dev/dri
|
||||
--cap-add CAP_SYS_ADMIN
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: projects/rocprofiler-compute/
|
||||
|
||||
- name: Update system packages
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get dist-upgrade -y
|
||||
echo "✅ System packages updated!"
|
||||
|
||||
- name: Install amdgpu and dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
ROCM_MAJOR=$(echo ${{ env.ROCM_VERSION }} | sed 's/\./ /g' | awk '{print $1}')
|
||||
ROCM_MINOR=$(echo ${{ env.ROCM_VERSION }} | sed 's/\./ /g' | awk '{print $2}')
|
||||
ROCM_VERSN=$(( (${ROCM_MAJOR}*10000)+(${ROCM_MINOR}*100) ))
|
||||
wget -N -P /tmp/ https://repo.radeon.com/amdgpu-install/${ROCM_MAJOR}.${ROCM_MINOR}/ubuntu/${{ matrix.system.code-name }}/amdgpu-install_${ROCM_MAJOR}.${ROCM_MINOR}.${ROCM_VERSN}-1_all.deb
|
||||
apt-get install -y /tmp/amdgpu-install_${ROCM_MAJOR}.${ROCM_MINOR}.${ROCM_VERSN}-1_all.deb
|
||||
apt-get update
|
||||
apt install -y amd-smi-lib libdw-dev
|
||||
echo "✅ amdgpu and dependencies Installed!"
|
||||
|
||||
- name: Install MPI
|
||||
run: |
|
||||
apt install -y libopenmpi-dev
|
||||
echo "✅ MPI Installed!"
|
||||
|
||||
- name: Install ROCm
|
||||
run: |
|
||||
apt install -y rocm-dev
|
||||
echo "✅ ROCm Installation Complete!"
|
||||
|
||||
- name: Install Python Dependencies
|
||||
working-directory: projects/rocprofiler-compute
|
||||
run: |
|
||||
pip install -r requirements.txt --break-system-packages --ignore-installed
|
||||
pip install -r requirements-test.txt --break-system-packages --ignore-installed
|
||||
echo "✅ Python dependencies installed!"
|
||||
|
||||
- name: Configure, Build, Test, and Upload Coverage
|
||||
id: run_coverage
|
||||
timeout-minutes: 120
|
||||
working-directory: projects/rocprofiler-compute
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set -e
|
||||
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
git config --global --add safe.directory ${PWD}
|
||||
|
||||
BUILD_NAME="ROCm/rocprofiler-compute-${{ github.ref_name }}-ubuntu-${{ matrix.system.os-release }}-${{ matrix.system.gpu }}"
|
||||
SITE_NAME="${{ matrix.system.runner }}"
|
||||
|
||||
PATH=${{ env.ROCM_PATH }}/bin:${{ env.ROCM_PATH }}/llvm/bin:$PATH \
|
||||
LD_LIBRARY_PATH=${{ env.ROCM_PATH }}/lib:${{ env.ROCM_PATH }}/llvm/lib:$LD_LIBRARY_PATH \
|
||||
python3 ./tools/run-ci.py \
|
||||
--build-name "${BUILD_NAME}" \
|
||||
--site "${SITE_NAME}" \
|
||||
--mode "Nightly" \
|
||||
--build-jobs 16 \
|
||||
--pytest-numprocs 8 \
|
||||
--install
|
||||
|
||||
- name: Check Coverage Configuration
|
||||
if: always()
|
||||
working-directory: projects/rocprofiler-compute
|
||||
run: |
|
||||
echo "=== Checking Build Configuration ==="
|
||||
if [ -f "build/CMakeCache.txt" ]; then
|
||||
echo "CMakeCache.txt contents (relevant variables):"
|
||||
grep -E "ENABLE_TESTS|ENABLE_COVERAGE|INSTALL_TESTS|PYTEST_NUMPROCS" build/CMakeCache.txt || echo "⚠️ Coverage variables not found!"
|
||||
echo ""
|
||||
echo "=== Checking for coverage.xml ==="
|
||||
if [ -f "build/coverage.xml" ]; then
|
||||
echo "✅ coverage.xml found!"
|
||||
ls -lh build/coverage.xml
|
||||
else
|
||||
echo "❌ coverage.xml NOT found!"
|
||||
fi
|
||||
echo ""
|
||||
echo "=== Checking CTest results ==="
|
||||
if [ -f "build/Testing/Temporary/LastTest.log" ]; then
|
||||
echo "Last 50 lines of test log:"
|
||||
tail -n 50 build/Testing/Temporary/LastTest.log
|
||||
fi
|
||||
else
|
||||
echo "❌ build/CMakeCache.txt not found - build may have failed!"
|
||||
fi
|
||||
|
||||
- name: Upload Logs on Failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-logs-${{ matrix.system.gpu }}-${{ matrix.system.os-release }}
|
||||
path: |
|
||||
projects/rocprofiler-compute/build/Testing/Temporary/LastTest*.log
|
||||
projects/rocprofiler-compute/build/coverage.xml
|
||||
retention-days: 7
|
||||
@@ -164,7 +164,7 @@ if(LOCALHOST MATCHES "TheraS01|.*\.thera\.amd\.com|thera-hn")
|
||||
file(READ ${PROJECT_SOURCE_DIR}/cmake/modfile.thera.mod mod_additions)
|
||||
file(
|
||||
APPEND
|
||||
${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${ROCPROFCOMPUTE_FULL_VERSION}.lua
|
||||
${PROJECT_BINARY_DIR}/${MOD_INSTALL_PATH}/${ROCPROFCOMPUTE_FULL_VERSION}.lua
|
||||
${mod_additions}
|
||||
)
|
||||
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
||||
@@ -336,7 +336,11 @@ set_tests_properties(
|
||||
test_profile_misc
|
||||
test_profile_path
|
||||
test_profile_roofline
|
||||
PROPERTIES LABELS "profile" RESOURCE_GROUPS gpus:1
|
||||
test_profile_section
|
||||
test_profile_pc_sampling
|
||||
test_profile_sets_func
|
||||
test_profile_live_attach_detach
|
||||
PROPERTIES LABELS "profile" RESOURCE_GROUPS gpus:1 TIMEOUT 1800
|
||||
)
|
||||
|
||||
# ---------------------------
|
||||
@@ -463,6 +467,7 @@ if(${ENABLE_COVERAGE})
|
||||
DEPENDS "${ALL_TESTS_STRING}"
|
||||
LABELS "coverage"
|
||||
ENVIRONMENT "COVERAGE_FILE=${PROJECT_SOURCE_DIR}/.coverage"
|
||||
TIMEOUT 600
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -489,8 +494,7 @@ install(
|
||||
src/config.py
|
||||
src/rocprof_compute_base.py
|
||||
src/roofline.py
|
||||
VERSION
|
||||
VERSION.sha
|
||||
VERSION VERSION.sha
|
||||
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${PROJECT_NAME}
|
||||
COMPONENT main
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,77 +0,0 @@
|
||||
# Coverage Workflow for rocprofiler-compute in Monorepo
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the coverage generation and CDash upload workflow for `rocprofiler-compute` within the super-repo structure.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
monorepo/
|
||||
├── projects/
|
||||
│ └── rocprofiler-compute/
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── coverage/
|
||||
│ │ └── coverage-latest.xml # committed coverage file
|
||||
│ ├── tools/
|
||||
│ │ ├── update_coverage.sh # coverage generation/update script
|
||||
│ │ └── run-ci.py # CDash upload script
|
||||
│ └── ...
|
||||
└── .github/
|
||||
└── workflows/
|
||||
└── rocprofiler-compute-cdash.yml # gitHub Action for auto-upload
|
||||
```
|
||||
|
||||
## Workflows
|
||||
|
||||
### 1. Manual Coverage Generation (Periodic Update)
|
||||
|
||||
Run this periodically to update the coverage baseline:
|
||||
|
||||
```bash
|
||||
# From monorepo root
|
||||
cd projects/rocprofiler-compute
|
||||
./tools/update_coverage.sh
|
||||
|
||||
# This will:
|
||||
# - Build with coverage enabled
|
||||
# - Run all tests
|
||||
# - Generate coverage.xml
|
||||
# - Copy/overwrite to coverage/coverage-latest.xml
|
||||
# - Show instructions for committing
|
||||
```
|
||||
|
||||
### 2. Commit Coverage to Repository
|
||||
|
||||
```bash
|
||||
# From monorepo root
|
||||
git add projects/rocprofiler-compute/coverage/coverage-latest.xml
|
||||
git commit -m "rocprofiler-compute: Update coverage to XX.X% line coverage"
|
||||
git push origin develop
|
||||
```
|
||||
|
||||
### 3. Automatic CDash Upload
|
||||
|
||||
When `coverage/coverage-latest.xml` is pushed to `develop` branch:
|
||||
- GitHub Action triggers automatically
|
||||
- Uploads coverage to CDash
|
||||
- Posts summary to GitHub Actions
|
||||
|
||||
## CDash Project
|
||||
|
||||
View results at: https://my.cdash.org/index.php?project=rocprofiler-compute
|
||||
|
||||
## Maintenance
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Coverage Generation Fails
|
||||
|
||||
```bash
|
||||
#check Python dependencies
|
||||
pip install coverage pytest pytest-cov
|
||||
|
||||
#verify tests can run
|
||||
cd projects/rocprofiler-compute/build
|
||||
ctest --verbose
|
||||
```
|
||||
@@ -1,10 +1,10 @@
|
||||
set(CMAKE_HIP_COMPILER "amdclang++" CACHE STRING "desired c++ compiler" FORCE)
|
||||
if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
|
||||
if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang" OR CMAKE_HIP_COMPILER_ID STREQUAL "ROCMClang")
|
||||
message(STATUS "Using ${CMAKE_HIP_COMPILER} to build for amdgpu backend")
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"'amdclang++' compiler required to compile test binaries for ROCm platform."
|
||||
"'amdclang++' compiler required to compile test binaries for ROCm platform. Found: ${CMAKE_HIP_COMPILER_ID}"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -23,13 +23,8 @@
|
||||
# THE SOFTWARE.
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
CI script to upload coverage XML files to CDash
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -60,16 +55,44 @@ def detect_repo_structure():
|
||||
return False, None, cwd
|
||||
|
||||
|
||||
def create_ctest_script(args):
|
||||
"""Generate a CTest script for uploading coverage data"""
|
||||
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()
|
||||
@@ -78,93 +101,143 @@ else()
|
||||
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 "{args.source_dir}")
|
||||
set(CTEST_BINARY_DIRECTORY "{args.binary_dir}")
|
||||
set(CTEST_SOURCE_DIRECTORY "{source_dir}")
|
||||
set(CTEST_BINARY_DIRECTORY "{binary_dir}")
|
||||
|
||||
file(MAKE_DIRECTORY "${{CTEST_BINARY_DIRECTORY}}")
|
||||
# Build config
|
||||
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
|
||||
set(CTEST_BUILD_CONFIGURATION "Release")
|
||||
|
||||
if(NOT EXISTS "${{CTEST_BINARY_DIRECTORY}}/CMakeCache.txt")
|
||||
file(WRITE "${{CTEST_BINARY_DIRECTORY}}/CMakeCache.txt"
|
||||
"CMAKE_PROJECT_NAME:STATIC={args.project_name}\\n")
|
||||
endif()
|
||||
# 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}")
|
||||
|
||||
file(WRITE "${{CTEST_BINARY_DIRECTORY}}/CTestConfig.cmake" "
|
||||
set(CTEST_PROJECT_NAME \\"{args.project_name}\\")
|
||||
set(CTEST_NIGHTLY_START_TIME \\"01:00:00 UTC\\")
|
||||
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()
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
")
|
||||
message(STATUS "CMake configure command: ${{CTEST_CONFIGURE_COMMAND}}")
|
||||
|
||||
message(STATUS "Starting {args.mode} dashboard...")
|
||||
ctest_start({args.mode})
|
||||
|
||||
set(COVERAGE_SRC_FILE "{args.coverage_file}")
|
||||
set(COVERAGE_DEST_FILE "${{CTEST_BINARY_DIRECTORY}}/coverage.xml")
|
||||
# Config step
|
||||
message(STATUS "Configuring project...")
|
||||
ctest_configure(
|
||||
RETURN_VALUE configure_result
|
||||
CAPTURE_CMAKE_ERROR configure_error
|
||||
)
|
||||
|
||||
if(NOT EXISTS "${{COVERAGE_SRC_FILE}}")
|
||||
message(FATAL_ERROR "Coverage file not found: ${{COVERAGE_SRC_FILE}}")
|
||||
if(configure_result OR configure_error)
|
||||
message(WARNING "Configuration had issues but continuing...")
|
||||
endif()
|
||||
|
||||
file(COPY "${{COVERAGE_SRC_FILE}}" DESTINATION "${{CTEST_BINARY_DIRECTORY}}")
|
||||
get_filename_component(SRC_FILENAME "${{COVERAGE_SRC_FILE}}" NAME)
|
||||
if(NOT SRC_FILENAME STREQUAL "coverage.xml")
|
||||
file(RENAME "${{CTEST_BINARY_DIRECTORY}}/${{SRC_FILENAME}}"
|
||||
"${{COVERAGE_DEST_FILE}}")
|
||||
# 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()
|
||||
|
||||
message(STATUS "Processing coverage file: ${{COVERAGE_DEST_FILE}}")
|
||||
# Test step
|
||||
message(STATUS "Running tests...")
|
||||
ctest_test(
|
||||
{test_args}
|
||||
PARALLEL_LEVEL 1
|
||||
RETURN_VALUE test_result
|
||||
CAPTURE_CMAKE_ERROR test_error
|
||||
)
|
||||
|
||||
file(MAKE_DIRECTORY "${{CTEST_BINARY_DIRECTORY}}/Testing")
|
||||
file(MAKE_DIRECTORY "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo")
|
||||
|
||||
file(COPY "${{COVERAGE_DEST_FILE}}"
|
||||
DESTINATION "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo")
|
||||
|
||||
ctest_coverage()
|
||||
|
||||
ctest_submit(PARTS Coverage
|
||||
RETRY_COUNT 3
|
||||
RETRY_DELAY 5
|
||||
CAPTURE_CMAKE_ERROR submit_error)
|
||||
|
||||
if(submit_error)
|
||||
message(FATAL_ERROR "Failed to submit coverage to CDash. "
|
||||
"Error code: ${{submit_error}}")
|
||||
if(test_result OR test_error)
|
||||
message(WARNING "Some tests failed but continuing with coverage and upload...")
|
||||
endif()
|
||||
|
||||
message(STATUS "Successfully submitted coverage to CDash")
|
||||
# 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():
|
||||
if not os.getenv("CI"):
|
||||
print("WARNING: CDash upload should normally only be done from CI/CD")
|
||||
response = input("Continue anyway? (y/N): ")
|
||||
if response.lower() != "y":
|
||||
print("Aborted.")
|
||||
return 1
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Upload coverage XML to CDash for rocprofiler-compute"
|
||||
description="CI script for rocprofiler-compute: build, test, and upload to CDash"
|
||||
)
|
||||
|
||||
# required
|
||||
parser.add_argument(
|
||||
"--coverage-file", required=True, help="Path to coverage XML file"
|
||||
"--build-name",
|
||||
"--name",
|
||||
dest="build_name",
|
||||
required=True,
|
||||
help="Build name for CDash",
|
||||
)
|
||||
parser.add_argument("--build-name", required=True, help="Build name for CDash")
|
||||
|
||||
# optional
|
||||
parser.add_argument(
|
||||
"--project-name", default="rocprofiler-compute", help="CDash project name"
|
||||
"--project-name",
|
||||
default="rocprofiler-compute",
|
||||
help="CDash project name",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--submit-url",
|
||||
@@ -172,7 +245,9 @@ def main():
|
||||
help="CDash submission URL",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cdash-host", default="my.cdash.org", help="CDash host (for older CMake)"
|
||||
"--cdash-host",
|
||||
default="my.cdash.org",
|
||||
help="CDash host (for older CMake)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--submit-path",
|
||||
@@ -186,11 +261,13 @@ def main():
|
||||
)
|
||||
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)",
|
||||
)
|
||||
@@ -201,10 +278,33 @@ def main():
|
||||
help="CTest dashboard mode",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run", action="store_true", help="Generate script but don't execute"
|
||||
"--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 = parser.parse_args()
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
args.cmake_args = []
|
||||
args.ctest_args = []
|
||||
|
||||
is_monorepo, monorepo_root, project_root = detect_repo_structure()
|
||||
|
||||
@@ -220,113 +320,83 @@ def main():
|
||||
else:
|
||||
args.site = os.uname().nodename
|
||||
|
||||
coverage_path = Path(args.coverage_file)
|
||||
if not coverage_path.is_absolute():
|
||||
if not coverage_path.exists():
|
||||
coverage_path = project_root / args.coverage_file
|
||||
|
||||
if not coverage_path.exists():
|
||||
print(f"ERROR: Coverage file not found: {coverage_path}", file=sys.stderr)
|
||||
print(f" Searched in: {Path(args.coverage_file).absolute()}")
|
||||
print(f" And in: {project_root / args.coverage_file}")
|
||||
return 1
|
||||
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
tree = ET.parse(coverage_path)
|
||||
root = tree.getroot()
|
||||
if root.tag != "coverage":
|
||||
print(
|
||||
f"ERROR: File does not appear to be a coverage XML file "
|
||||
f"(root tag: {root.tag})",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
line_rate = float(root.get("line-rate", 0)) * 100
|
||||
print(f"Line Coverage: {line_rate:.1f}%")
|
||||
except Exception as e:
|
||||
print(f"ERROR: Could not parse coverage XML file: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
args.coverage_file = str(coverage_path.absolute())
|
||||
args.source_dir = str(Path(args.source_dir).absolute())
|
||||
args.binary_dir = str(Path(args.binary_dir).absolute())
|
||||
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"Project root: {project_root}")
|
||||
print(f"Uploading coverage file: {args.coverage_file}")
|
||||
print(f"Source directory: {source_dir}")
|
||||
print(f"Binary directory: {binary_dir}")
|
||||
print(f"Build name: {args.build_name}")
|
||||
print(f"Project: {args.project_name}")
|
||||
print(f"Dashboard mode: {args.mode}")
|
||||
print(f"CDash project: {args.project_name}")
|
||||
print(f"Site: {args.site}")
|
||||
print(f"Submit URL: {args.submit_url}")
|
||||
print("=" * 80)
|
||||
|
||||
# Ensure build directory exists
|
||||
os.makedirs(args.binary_dir, exist_ok=True)
|
||||
|
||||
# Copy CTestConfig.cmake if it exists in source
|
||||
source_ctest_config = Path(args.source_dir) / "CTestConfig.cmake"
|
||||
if source_ctest_config.exists():
|
||||
shutil.copy2(source_ctest_config, Path(args.binary_dir) / "CTestConfig.cmake")
|
||||
print("Copied CTestConfig.cmake to build directory")
|
||||
|
||||
script_content = create_ctest_script(args)
|
||||
script_content = generate_ctest_dashboard_script(args, source_dir, binary_dir)
|
||||
|
||||
if args.dry_run:
|
||||
print("\nGenerated CTest script:")
|
||||
print("=" * 50)
|
||||
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:
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".cmake", delete=False) as f:
|
||||
f.write(script_content)
|
||||
script_path = f.name
|
||||
|
||||
print(f"\nScript written to: {script_path}")
|
||||
|
||||
original_dir = os.getcwd()
|
||||
os.chdir(args.source_dir)
|
||||
|
||||
cmd = ["ctest", "-S", script_path, "-V"]
|
||||
print(f"Executing: {' '.join(cmd)}")
|
||||
print(f"Working directory: {os.getcwd()}")
|
||||
print(f"Running: {' '.join(cmd)}")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if result.stdout:
|
||||
print("\nSTDOUT:")
|
||||
print(result.stdout)
|
||||
|
||||
if result.stderr:
|
||||
print("\nSTDERR:")
|
||||
print(result.stderr)
|
||||
|
||||
os.chdir(original_dir)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"\nCTest failed with return code: {result.returncode}")
|
||||
return result.returncode
|
||||
|
||||
print("\n✅ Coverage successfully uploaded to CDash!")
|
||||
cdash_url = args.submit_url.replace(
|
||||
"/submit.php?project=", "/index.php?project="
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=source_dir,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
universal_newlines=True,
|
||||
)
|
||||
print(f"View results at: {cdash_url}")
|
||||
return 0
|
||||
|
||||
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"Error executing CTest script: {e}", file=sys.stderr)
|
||||
print(f"\n❌ Error executing dashboard script: {e}", file=sys.stderr)
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
finally:
|
||||
if "script_path" in locals():
|
||||
try:
|
||||
os.unlink(script_path)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
os.unlink(script_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/bin/bash
|
||||
##############################################################################
|
||||
# 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.
|
||||
##############################################################################
|
||||
|
||||
# generate_coverage.sh
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
BUILD_DIR="$PROJECT_ROOT/build"
|
||||
COVERAGE_FILE="$PROJECT_ROOT/coverage/Coverage.xml"
|
||||
|
||||
echo "=== Generating Coverage for Mainline Promotion ==="
|
||||
|
||||
echo "Setting up clean build..."
|
||||
rm -rf "$BUILD_DIR"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
echo "Configuring with coverage enabled..."
|
||||
cmake -DENABLE_COVERAGE=ON -DENABLE_TESTS=ON -DPYTEST_NUMPROCS=8 ..
|
||||
|
||||
echo "Building..."
|
||||
make -j$(nproc)
|
||||
|
||||
echo "Running ALL tests to generate coverage (this may take a while)..."
|
||||
ctest --verbose --output-on-failure --parallel 1 || {
|
||||
echo "WARNING: Some tests failed, but continuing with coverage generation"
|
||||
}
|
||||
|
||||
echo "Generating coverage report..."
|
||||
ctest -R generate_coverage_report --output-on-failure --parallel 2
|
||||
|
||||
if [ ! -f "coverage.xml" ]; then
|
||||
echo "ERROR: coverage.xml not generated"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COVERAGE_INFO=$(python3 -c "
|
||||
import xml.etree.ElementTree as ET
|
||||
tree = ET.parse('coverage.xml')
|
||||
root = tree.getroot()
|
||||
line_rate = float(root.get('line-rate', 0)) * 100
|
||||
print(f'{line_rate:.1f}%')
|
||||
")
|
||||
|
||||
mkdir -p "$PROJECT_ROOT/coverage"
|
||||
cp coverage.xml "$COVERAGE_FILE"
|
||||
|
||||
echo ""
|
||||
echo "=== Coverage Generated Successfully ==="
|
||||
echo "Line Coverage: $COVERAGE_INFO"
|
||||
echo "File: $COVERAGE_FILE"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. git add $COVERAGE_FILE"
|
||||
echo "2. git commit -m 'Update coverage: $COVERAGE_INFO'"
|
||||
echo "3. Proceed with push to develop"
|
||||
echo "4. CDash upload will happen automatically on push"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user