Files
TheRock/rocm-systems/projects/rocshmem/scripts/functional_tests/run_perf_compare.sh
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

377 lines
15 KiB
Bash
Executable File

#!/bin/bash
###############################################################################
# Performance Regression Comparison
#
# Compares one or more build variants against a baseline. By default compares
# the current branch against its merge-base with origin/develop.
#
# Usage:
# ./scripts/functional_tests/run_perf_compare.sh [OPTIONS]
#
# Options:
# --iterations N Number of test iterations per config (default: 10)
# --suite SUITE Test suite: "heatmap", "all", "rma", etc (default: heatmap)
# --build-config CFG Build config script name under scripts/build_configs/
# (default: all_backends)
# --cmake-args ARGS Extra cmake args for all builds (quoted string)
# --branch-args ARGS Extra cmake args for the branch build only (quoted string)
# --variant-args SPEC Additional named variant: NAME:ENV1=V1,...:cmake-args
# NAME - label used in plots and directory name
# ENV1=V1,… - comma-separated env vars set at runtime
# cmake-args - extra cmake args for this variant's build
# May be repeated for multiple variants.
# Example: --variant-args "sdma-on:ROCSHMEM_SDMA_ENABLED=1:-DUSE_SDMA=ON"
# --pr NUM Compare GitHub PR NUM against origin/develop baseline.
# Fetches the PR branch, builds it, and names it "pr<NUM>".
# --base-branch NAME Base branch to compare against (default: origin/develop)
# --baseline-dir PATH Use PATH as pre-built baseline (skips baseline build).
# Use with --skip-baseline to also skip baseline test runs.
# --branch-dir PATH Use PATH as pre-built branch build (skips branch build).
# --skip-build Skip all build steps (reuse existing builds)
# --skip-baseline Skip baseline build and test runs (reuse existing logs)
# --skip-develop Alias for --skip-baseline
# --skip-branch Skip branch/PR build and test runs (reuse existing logs)
# --outdir DIR Output directory for plots (default: auto-generated)
#
# Prerequisites:
# - Open MPI in PATH (or set OMPI_HOME)
# - ROCm installed at /opt/rocm
# - Python 3.x with ensurepip (python3-venv package on Debian/Ubuntu)
#
# Output:
# <outdir>/heatmap_summary.png Summary heatmap
# <outdir>/per_test/*.png Per-test latency curves
# <outdir>/heatmap_data.csv Raw percentage data
###############################################################################
set -euo pipefail
# ---------------------------------------------------------------------------
# Defaults
# ---------------------------------------------------------------------------
ITERATIONS=10
SUITE=heatmap
BUILD_CONFIG=all_backends
CMAKE_ARGS=""
BRANCH_ARGS=""
VARIANT_SPECS=() # array of "name:env1=v1,...:cmake-args"
PR_NUM=""
SKIP_BUILD=0
SKIP_BASELINE=0
SKIP_BRANCH=0
BASE_BRANCH="origin/develop"
BASELINE_DIR=""
BRANCH_DIR=""
OUTDIR=""
while [[ $# -gt 0 ]]; do
case "$1" in
--iterations) ITERATIONS="$2"; shift 2 ;;
--suite) SUITE="$2"; shift 2 ;;
--build-config) BUILD_CONFIG="$2"; shift 2 ;;
--cmake-args) CMAKE_ARGS="$2"; shift 2 ;;
--branch-args) BRANCH_ARGS="$2"; shift 2 ;;
--variant-args) VARIANT_SPECS+=("$2"); shift 2 ;;
--pr) PR_NUM="$2"; shift 2 ;;
--base-branch) BASE_BRANCH="$2"; shift 2 ;;
--baseline-dir) BASELINE_DIR="$2"; shift 2 ;;
--branch-dir) BRANCH_DIR="$2"; shift 2 ;;
--skip-build) SKIP_BUILD=1; shift ;;
--skip-baseline) SKIP_BASELINE=1; shift ;;
--skip-develop) SKIP_BASELINE=1; shift ;;
--skip-branch) SKIP_BRANCH=1; shift ;;
--outdir) OUTDIR="$2"; shift 2 ;;
-h|--help)
sed -n '2,/^###$/p' "$0" | head -n -1
exit 0 ;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROCSHMEM_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
PROJECTS_DIR="$(cd "$ROCSHMEM_DIR/.." && pwd)"
DRIVER="$ROCSHMEM_DIR/scripts/functional_tests/driver.sh"
COMPARE="$ROCSHMEM_DIR/scripts/functional_tests/perf_compare.py"
VENV_DIR="$SCRIPT_DIR/.perf-venv"
# Open MPI
export PATH="${OMPI_HOME:-$HOME/ompi}/bin:$PATH"
export LD_LIBRARY_PATH="${OMPI_HOME:-$HOME/ompi}/lib:${LD_LIBRARY_PATH:-}"
# ---------------------------------------------------------------------------
# Determine branch label and build directories
# ---------------------------------------------------------------------------
cd "$ROCSHMEM_DIR"
if [[ -n "$PR_NUM" ]]; then
# PR mode: compare PR branch against develop baseline
BRANCH_LABEL="pr${PR_NUM}"
BRANCH_SAFE="pr${PR_NUM}"
BUILD_BASELINE="${BASELINE_DIR:-$PROJECTS_DIR/build-develop}"
BUILD_BRANCH="${BRANCH_DIR:-$PROJECTS_DIR/build-${BRANCH_SAFE}}"
[[ -z "$OUTDIR" ]] && OUTDIR="$PROJECTS_DIR/plots-${SUITE}-${BRANCH_SAFE}"
echo "================================================================================"
echo "Performance Comparison (PR mode)"
echo " PR: #${PR_NUM}"
echo " Base branch: $BASE_BRANCH"
echo " Suite: $SUITE"
echo " Iterations: $ITERATIONS"
echo " Build cfg: $BUILD_CONFIG"
echo " Baseline: $BUILD_BASELINE"
echo " Branch: $BUILD_BRANCH"
echo " Output: $OUTDIR"
echo "================================================================================"
else
# Default mode: current branch vs merge-base
BRANCH_NAME="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "detached")"
if [[ "$BRANCH_NAME" == "HEAD" || "$BRANCH_NAME" == "detached" ]]; then
BRANCH_NAME="$(git rev-parse --short HEAD)"
fi
MERGE_BASE="$(git merge-base HEAD "$BASE_BRANCH" 2>/dev/null)" || {
echo "ERROR: Cannot find merge-base between HEAD and $BASE_BRANCH" >&2
echo " Make sure '$BASE_BRANCH' exists (try: git fetch origin)" >&2
exit 1
}
MERGE_BASE_SHORT="$(git rev-parse --short "$MERGE_BASE")"
BRANCH_LABEL="$BRANCH_NAME"
BRANCH_SAFE="$(echo "$BRANCH_NAME" | tr '/' '-' | tr -cd '[:alnum:]-_.')"
BUILD_BASELINE="${BASELINE_DIR:-$PROJECTS_DIR/build-baseline-$MERGE_BASE_SHORT}"
BUILD_BRANCH="${BRANCH_DIR:-$PROJECTS_DIR/build-branch-$BRANCH_SAFE}"
[[ -z "$OUTDIR" ]] && OUTDIR="$PROJECTS_DIR/plots-${SUITE}-${BRANCH_SAFE}"
echo "================================================================================"
echo "Performance Comparison"
echo " Branch: $BRANCH_NAME"
echo " Base branch: $BASE_BRANCH"
echo " Merge-base: $MERGE_BASE_SHORT"
echo " Suite: $SUITE"
echo " Iterations: $ITERATIONS"
echo " Build cfg: $BUILD_CONFIG"
echo " Baseline: $BUILD_BASELINE"
echo " Branch: $BUILD_BRANCH"
echo " Output: $OUTDIR"
echo "================================================================================"
fi
# ---------------------------------------------------------------------------
# Step 0: Python virtual environment
# ---------------------------------------------------------------------------
echo ""
echo ">>> Step 0: Setting up Python virtual environment"
# Self-healing: if the venv exists but is missing required packages, recreate it.
if [[ -d "$VENV_DIR" ]] && \
! "$VENV_DIR/bin/python3" -c "import matplotlib, numpy, pandas, seaborn" &>/dev/null; then
echo " Existing venv is missing dependencies, recreating..."
rm -rf "$VENV_DIR"
fi
if [[ ! -d "$VENV_DIR" ]]; then
# Try a fully isolated venv first (requires python3-venv / ensurepip).
# Fall back to --system-site-packages --without-pip when ensurepip is
# unavailable (e.g. Debian/Ubuntu without python3.x-venv installed).
if python3 -m ensurepip --version &>/dev/null; then
python3 -m venv "$VENV_DIR" || { echo "ERROR: Failed to create venv." >&2; exit 1; }
else
python3 -m venv --system-site-packages --without-pip "$VENV_DIR" || {
echo "ERROR: Failed to create venv (even without pip)." >&2; exit 1
}
fi
"$VENV_DIR/bin/python3" -m pip install --quiet matplotlib numpy pandas seaborn || {
echo "ERROR: Failed to install Python dependencies." >&2
echo " If using system pip, try: sudo apt install python3-pip" >&2
exit 1
}
echo " Created venv and installed dependencies at $VENV_DIR"
else
echo " Reusing existing venv at $VENV_DIR"
fi
PYTHON="$VENV_DIR/bin/python3"
# ---------------------------------------------------------------------------
# Step 1: Build
# ---------------------------------------------------------------------------
_find_build_config() {
local worktree="$1"
local config="$2"
local result=""
for candidate in \
"$worktree/scripts/build_configs/$config" \
"$worktree/projects/rocshmem/scripts/build_configs/$config"; do
if [[ -x "$candidate" ]]; then
result="$candidate"
break
fi
done
echo "$result"
}
if [[ $SKIP_BUILD -eq 0 ]]; then
echo ""
echo ">>> Step 1: Building configurations"
# Locate branch build config
BUILD_CONFIG_SCRIPT="$ROCSHMEM_DIR/scripts/build_configs/$BUILD_CONFIG"
if [[ ! -x "$BUILD_CONFIG_SCRIPT" ]]; then
echo "ERROR: Build config not found: $BUILD_CONFIG_SCRIPT" >&2
exit 1
fi
# Build baseline
if [[ $SKIP_BASELINE -eq 0 && -z "$BASELINE_DIR" ]]; then
echo "--- Building baseline ---"
WORKTREE="/tmp/rocshmem-baseline-$$"
if [[ -n "$PR_NUM" ]]; then
# PR mode: checkout develop
git -C "$ROCSHMEM_DIR" worktree add "$WORKTREE" "$BASE_BRANCH" --detach 2>&1
else
# Default mode: checkout merge-base
git -C "$ROCSHMEM_DIR" worktree add "$WORKTREE" "$MERGE_BASE" --detach 2>&1
fi
BASELINE_CONFIG="$(_find_build_config "$WORKTREE" "$BUILD_CONFIG")"
if [[ -z "$BASELINE_CONFIG" ]]; then
echo "ERROR: Cannot find $BUILD_CONFIG in baseline worktree" >&2
git -C "$ROCSHMEM_DIR" worktree remove "$WORKTREE" 2>/dev/null || true
exit 1
fi
mkdir -p "$BUILD_BASELINE"
rm -f "$BUILD_BASELINE/CMakeCache.txt"
(cd "$BUILD_BASELINE" && "$BASELINE_CONFIG" $CMAKE_ARGS)
git -C "$ROCSHMEM_DIR" worktree remove "$WORKTREE" 2>/dev/null || true
else
echo "--- Skipping baseline build ---"
fi
# Build branch
if [[ $SKIP_BRANCH -eq 1 ]]; then
echo "--- Skipping branch build ---"
elif [[ -z "$BRANCH_DIR" ]]; then
if [[ -n "$PR_NUM" ]]; then
echo "--- Fetching and building PR #${PR_NUM} ---"
WORKTREE="/tmp/rocshmem-pr${PR_NUM}-$$"
git -C "$ROCSHMEM_DIR" fetch origin "pull/${PR_NUM}/head"
git -C "$ROCSHMEM_DIR" worktree add "$WORKTREE" FETCH_HEAD --detach 2>&1
PR_CONFIG="$(_find_build_config "$WORKTREE" "$BUILD_CONFIG")"
if [[ -z "$PR_CONFIG" ]]; then
echo "ERROR: Cannot find $BUILD_CONFIG in PR worktree" >&2
git -C "$ROCSHMEM_DIR" worktree remove "$WORKTREE" 2>/dev/null || true
exit 1
fi
mkdir -p "$BUILD_BRANCH"
(cd "$BUILD_BRANCH" && "$PR_CONFIG" $CMAKE_ARGS $BRANCH_ARGS)
git -C "$ROCSHMEM_DIR" worktree remove "$WORKTREE" 2>/dev/null || true
else
echo "--- Building branch ($BRANCH_LABEL) ---"
mkdir -p "$BUILD_BRANCH"
(cd "$BUILD_BRANCH" && "$BUILD_CONFIG_SCRIPT" $CMAKE_ARGS $BRANCH_ARGS)
fi
else
echo "--- Using pre-built branch dir: $BRANCH_DIR ---"
fi
# Build additional variants
for spec in "${VARIANT_SPECS[@]}"; do
IFS=':' read -r vname _venv vcmake <<< "$spec"
vdir="$PROJECTS_DIR/build-${BRANCH_SAFE}-${vname}"
echo "--- Building variant: $vname ---"
mkdir -p "$vdir"
(cd "$vdir" && "$BUILD_CONFIG_SCRIPT" $CMAKE_ARGS $vcmake)
done
echo ">>> Builds complete"
else
echo ""
echo ">>> Step 1: Skipping build (--skip-build)"
fi
# ---------------------------------------------------------------------------
# Step 2: Run tests
# ---------------------------------------------------------------------------
echo ""
echo ">>> Step 2: Running $SUITE tests ($ITERATIONS iterations)"
run_iterations() {
local build_dir="$1"
local log_prefix="$2"
local label="$3"
local env_prefix="${4:-}"
for i in $(seq 1 "$ITERATIONS"); do
printf " %-24s iteration %2d/%d\n" "$label" "$i" "$ITERATIONS"
(
cd "$build_dir"
if [[ -n "$env_prefix" ]]; then
eval "$env_prefix" "$DRIVER" tests/functional_tests/rocshmem_functional_tests \
"$SUITE" "${log_prefix}-${i}" 2>&1 | tail -1
else
"$DRIVER" tests/functional_tests/rocshmem_functional_tests \
"$SUITE" "${log_prefix}-${i}" 2>&1 | tail -1
fi
)
done
}
if [[ $SKIP_BASELINE -eq 0 ]]; then
run_iterations "$BUILD_BASELINE" "logs-${SUITE}" "baseline"
else
echo " Skipping baseline test runs (--skip-baseline)"
fi
if [[ $SKIP_BRANCH -eq 0 ]]; then
run_iterations "$BUILD_BRANCH" "logs-${SUITE}" "${BRANCH_LABEL}"
else
echo " Skipping branch test runs (--skip-branch)"
fi
for spec in "${VARIANT_SPECS[@]}"; do
IFS=':' read -r vname venv _vcmake <<< "$spec"
vdir="$PROJECTS_DIR/build-${BRANCH_SAFE}-${vname}"
env_prefix=""
IFS=',' read -ra pairs <<< "$venv"
for pair in "${pairs[@]}"; do
[[ -n "$pair" ]] && env_prefix+="export $pair; "
done
run_iterations "$vdir" "logs-${SUITE}" "$vname" "$env_prefix"
done
echo ">>> All test runs complete"
# ---------------------------------------------------------------------------
# Step 3: Generate comparison
# ---------------------------------------------------------------------------
echo ""
echo ">>> Step 3: Generating comparison plots"
# Build --variants args: always include the branch, then extra variants
VARIANT_ARGS=("${BRANCH_LABEL}:$BUILD_BRANCH/logs-${SUITE}-*")
for spec in "${VARIANT_SPECS[@]}"; do
IFS=':' read -r vname venv vcmake <<< "$spec"
vdir="$PROJECTS_DIR/build-${BRANCH_SAFE}-${vname}"
VARIANT_ARGS+=("${vname}:${vdir}/logs-${SUITE}-*")
done
"$PYTHON" "$COMPARE" \
--baseline "$BUILD_BASELINE/logs-${SUITE}-*" \
--variants "${VARIANT_ARGS[@]}" \
--outdir "$OUTDIR"
echo ""
echo "================================================================================"
echo "DONE"
echo " Heatmap: $OUTDIR/heatmap_summary.png"
echo " Summary: $OUTDIR/heatmap_summary.txt"
echo " CSV data: $OUTDIR/heatmap_data.csv"
echo " Per-test: $OUTDIR/per_test/ (*.png + *.txt)"
echo "================================================================================"