Files
TheRock/rocm-systems/.github/workflows/rccl-suite.yml
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

263 lines
11 KiB
YAML

name: RCCL suite
# Generic single-node launcher for an RCCL cluster test suite. Reusable (called
# by rccl-ci.yml; also runnable via workflow_dispatch). The `suite` input drives
# everything suite-specific: it selects lib/<suite>.sbatch, the .ci-out/<suite>-logs
# dir, and the rccl-<suite>-* scheduler stream, so gin and device-API share this
# one workflow.
#
# Per leg: checkout sources, provision ROCm on the head node (lib/fetch-rocm.sh),
# then `sbatch --wait` the compute-node script and dump its logs. ROCm/OpenMPI are
# version-keyed on the cluster-local cache (cache_root); RCCL/rccl-tests rebuild
# each run. `runs_on`, `cache_root`, and `partition` select the cluster, so a
# self-contained suite can run on any runner.
on:
workflow_call:
inputs:
suite:
description: 'Suite to run; selects lib/<suite>.sbatch (e.g. "gin", "device-api").'
type: string
required: true
runs_on:
description: 'Runner label(s) as a JSON array string; lets a suite target a specific cluster.'
type: string
required: false
default: '["ruby-linux-slurm-scale-runner"]'
cache_root:
description: 'Cluster-local ROCm/OpenMPI cache root (RCCL_DEVICE_API_CACHE).'
type: string
required: false
default: '/apps/rccl-ci'
partition:
description: 'SLURM partition for the compute-node job.'
type: string
required: false
default: 'interactive'
reservation:
description: 'SLURM reservation to pin the compute-node job to (e.g. "rccl_ci"). Empty = none.'
type: string
required: false
default: ''
rocm_release:
description: 'ROCm version prefix (e.g. "7.14" = newest 7.14.*; "7.14.0rc1" pins exactly). Empty = newest available.'
type: string
required: false
default: '7.14'
rocm_amdgpu_family:
description: 'Specific GPU family fallback if no multi-arch tarball is found.'
type: string
required: false
default: 'gfx950-dcgpu'
amdgpu_targets:
description: 'GPU arch for rocSHMEM/RCCL/rccl-tests (must match the ROCm family ARCH).'
type: string
required: false
default: 'gfx950'
non_gating:
description: 'If true, a suite failure does not fail the workflow (continue-on-error).'
type: boolean
required: false
default: false
timeout_minutes:
description: 'Job timeout in minutes.'
type: number
required: false
default: 240
outputs:
build_failed:
# true for a build/infra failure, false for a test-only failure. Lets the
# caller gate builds while keeping tests non-gating. AICOMRCCL-1478.
description: 'true if a build/infra step failed (not a test-only failure).'
value: ${{ jobs.suite.outputs.build_failed }}
workflow_dispatch:
inputs:
suite:
description: 'Suite to run; selects lib/<suite>.sbatch.'
type: choice
required: true
options:
- device-api
- gin
runs_on:
description: 'Runner label(s) as a JSON array string.'
type: string
required: false
default: '["ruby-linux-slurm-scale-runner"]'
cache_root:
description: 'Cluster-local ROCm/OpenMPI cache root (RCCL_DEVICE_API_CACHE).'
type: string
required: false
default: '/apps/rccl-ci'
partition:
description: 'SLURM partition for the compute-node job.'
type: string
required: false
default: 'interactive'
reservation:
description: 'SLURM reservation to pin the compute-node job to (e.g. "rccl_ci"). Empty = none.'
type: string
required: false
default: ''
rocm_release:
description: 'ROCm version prefix (e.g. "7.14"; "7.14.0rc1" pins exactly). Empty = newest available. Cascades release -> prerelease -> nightly, multiarch-first.'
type: string
required: false
default: '7.14'
rocm_amdgpu_family:
description: 'Specific GPU family fallback if no multi-arch tarball is found.'
type: string
required: false
default: 'gfx950-dcgpu'
amdgpu_targets:
description: 'GPU arch for rocSHMEM/RCCL/rccl-tests (must match the ROCm family ARCH).'
type: string
required: false
default: 'gfx950'
non_gating:
description: 'If true, a suite failure does not fail the workflow.'
type: boolean
required: false
default: false
timeout_minutes:
# workflow_dispatch has no number type; job timeout-minutes coerces it.
description: 'Job timeout in minutes.'
type: string
required: false
default: '240'
permissions:
contents: read
jobs:
suite:
name: Single node ${{ inputs.suite }} testing
runs-on: ${{ fromJSON(inputs.runs_on) }}
timeout-minutes: ${{ inputs.timeout_minutes }}
continue-on-error: ${{ inputs.non_gating }}
outputs:
build_failed: ${{ steps.classify.outputs.build_failed }}
defaults:
run:
shell: bash
env:
SUITE: ${{ inputs.suite }}
# Cluster-local ROCm/OpenMPI cache root.
RCCL_DEVICE_API_CACHE: ${{ inputs.cache_root }}
# SLURM partition for this cluster's compute-node job.
RCCL_SLURM_PARTITION: ${{ inputs.partition }}
# Optional SLURM reservation (e.g. dedicated CI nodes); empty = none.
RCCL_SLURM_RESERVATION: ${{ inputs.reservation }}
RCCL_AMDGPU_TARGETS: ${{ inputs.amdgpu_targets }}
ROCM_AMDGPU_FAMILY: ${{ inputs.rocm_amdgpu_family }}
# ROCM_RELEASE is a version prefix (e.g. "7.14"); empty => newest available.
ROCM_RELEASE: ${{ inputs.rocm_release }}
# Stability-first cascade used by fetch-rocm.sh (no token needed).
RCCL_ROCM_CHANNELS: 'release prerelease nightly'
# Add the test matrix's debug_env (NCCL_DEBUG=INFO, ...) to every run.
RCCL_CI_DEBUG: '1'
# Per-(run, attempt) checkout+build dir so parallel legs on the shared NFS
# _work never collide.
CI_SUBDIR: _ci/${{ inputs.suite }}-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
path: ${{ env.CI_SUBDIR }}
# Sources built by the compute-node script (rocSHMEM only used by gin).
sparse-checkout: |
projects/rccl
projects/rccl-tests
projects/rocshmem
- name: Provision ROCm (${{ inputs.rocm_release || 'latest' }}) on the head node
id: provision
run: |
set -euo pipefail
export RCCL_DEVICE_API_WORKDIR="${GITHUB_WORKSPACE}/${CI_SUBDIR}"
# Shared, version-keyed ROCm/OpenMPI cache on /apps NFS (safe to share).
export RCCL_DEVICE_API_CACHE="${RCCL_DEVICE_API_CACHE:-/apps/rccl-ci}"
echo "Workdir: ${RCCL_DEVICE_API_WORKDIR}"
echo "Cache root: ${RCCL_DEVICE_API_CACHE}"
if ! mkdir -p "${RCCL_DEVICE_API_CACHE}"/{rocm,ompi,downloads}; then
echo "ERROR: cannot create ${RCCL_DEVICE_API_CACHE} (is /apps writable by $(id -un)?)" >&2
exit 1
fi
"${RCCL_DEVICE_API_WORKDIR}/projects/rccl/tools/ci/lib/fetch-rocm.sh"
- name: Submit ${{ inputs.suite }} build+test to SLURM
id: submit
run: |
set -euo pipefail
export RCCL_DEVICE_API_WORKDIR="${GITHUB_WORKSPACE}/${CI_SUBDIR}"
export RCCL_DEVICE_API_CACHE="${RCCL_DEVICE_API_CACHE:-/apps/rccl-ci}"
echo "Cache root: ${RCCL_DEVICE_API_CACHE}"
ci_lib="${RCCL_DEVICE_API_WORKDIR}/projects/rccl/tools/ci/lib"
# submit_slurm_job.py does sbatch --wait + sacct cross-check (a bare
# --wait exits 0 even for scheduler-killed jobs).
python3 "${ci_lib}/submit_slurm_job.py" \
--script "${ci_lib}/${SUITE}.sbatch" \
--chdir "${RCCL_DEVICE_API_WORKDIR}/.ci-out/${SUITE}-logs" \
--partition "${RCCL_SLURM_PARTITION}" \
--reservation "${RCCL_SLURM_RESERVATION}" \
--export "ALL,RCCL_DEVICE_API_WORKDIR,RCCL_DEVICE_API_CACHE,ROCM_RELEASE,ROCM_AMDGPU_FAMILY,RCCL_AMDGPU_TARGETS,RCCL_CI_DEBUG"
- name: Dump compute-node logs
if: always()
run: |
logs_dir="${GITHUB_WORKSPACE}/${CI_SUBDIR}/.ci-out/${SUITE}-logs"
shopt -s nullglob
# One collapsible group per log; rccl-<suite>-* is SLURM's whole-job
# stream, kept last as a fallback for early/killed jobs.
dump() {
local title="$1"; shift
for f in "$@"; do
echo "::group::${title}: $(basename "${f}")"
cat "${f}" || true
echo "::endgroup::"
done
}
dump "build" "${logs_dir}"/build-*.out "${logs_dir}"/build-*.err
dump "test" "${logs_dir}"/test-*.out "${logs_dir}"/test-*.err
dump "scheduler" "${logs_dir}"/rccl-${SUITE}-*.out "${logs_dir}"/rccl-${SUITE}-*.err
# Verbose per-rank NCCL debug logs (RCCL_CI_DEBUG=1); noisy, kept last.
dump "nccl-debug" "${logs_dir}"/nccl-debug/nccl-debug.*.log
# Test-only failure (sbatch drops a `tests-failed` sentinel, exits 0): turn
# this job red here, where the logs are. AICOMRCCL-1478.
- name: Fail on test failures
if: always()
run: |
sentinel="${GITHUB_WORKSPACE}/${CI_SUBDIR}/.ci-out/${SUITE}-logs/tests-failed"
if [[ ! -f "${sentinel}" ]]; then
echo "${SUITE}: no test failures."
exit 0
fi
# Surface the failed/skipped list on the job Summary tab, not just the log.
{
echo "### ${SUITE}: tests failed"
echo ""
echo '```'
cat "${sentinel}"
echo '```'
echo ""
echo "_Full per-test output: the \`test\` log group of this job. Per-rank NCCL logs: the \`nccl-debug\` group._"
} >> "${GITHUB_STEP_SUMMARY}"
echo "::error::${SUITE} tests failed. See this job's Summary tab for the failed-test list."
exit 1
# Tell the caller whether this was a build/infra failure (gating) or a
# test-only failure (non-gating for gin). AICOMRCCL-1478.
- name: Classify failure
id: classify
if: always()
run: |
if [[ "${{ steps.provision.outcome }}" == "failure" || "${{ steps.submit.outcome }}" == "failure" ]]; then
echo "build_failed=true" >> "${GITHUB_OUTPUT}"
else
echo "build_failed=false" >> "${GITHUB_OUTPUT}"
fi
- name: Clean up per-job workdir
if: always()
run: rm -rf "${GITHUB_WORKSPACE:?}/${CI_SUBDIR:?}"