Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ee4ea1a
fix(rccl): score madengine training runs on the running-average throu…
mkuznet1 Oct 5, 2026
1226015
fix(rccl): point llama-4-scout at its own multiple_results CSV
mkuznet1 Oct 5, 2026
4d0a68a
feat(rccl): score the madengine gate against a same-node baseline
mkuznet1 Oct 6, 2026
ec19e97
ci(rccl): bump the madengine pin to 10a0414 (madengine#213)
mkuznet1 Oct 6, 2026
4cb6bbd
ci(rccl): run madengine from a conda env the compute nodes can execute
mkuznet1 Oct 6, 2026
2bd3dae
ci(rccl): name the baseline and candidate RCCL builds in the madengin…
mkuznet1 Oct 7, 2026
84a5816
ci(rccl): upload the madengine results from each A/B phase directory
mkuznet1 Oct 7, 2026
d0fdac6
ci(rccl): pin madengine at #213 rebased on #190; drop the template patch
mkuznet1 Oct 12, 2026
81523a9
fix(rccl): give each A/B phase the allocation's time limit
mkuznet1 Oct 12, 2026
165ec7c
ci(rccl): pin madengine on ROCm develop and MAD on the current mad-rccl
mkuznet1 Oct 14, 2026
02fe825
fix(rccl): fail the A/B when an expected precision is missing from bo…
mkuznet1 Oct 14, 2026
dfc2388
fix(rccl): keep each workload's archived results apart; lock the data…
mkuznet1 Oct 14, 2026
c27329f
docs(rccl): state what the madengine gate does, not how it got there
mkuznet1 Oct 14, 2026
f85ed45
fix(rccl): cancel the allocation when the A/B times out
mkuznet1 Oct 14, 2026
bb20fbc
fix(rccl): expect BF16 from llama-4-scout too
mkuznet1 Oct 14, 2026
76fe419
fix(rccl): keep conda and pip out of the runner account's home
mkuznet1 Oct 19, 2026
7cd9603
fix(rccl-ci): build the madengine overlay only on the compute nodes
mkuznet1 Oct 20, 2026
36b8720
fix(rccl-ci): tighten the same-node A/B gate and its cleanup
mkuznet1 Oct 22, 2026
3abc26e
fix(rccl-ci): never pull an image to clean up a node workspace
mkuznet1 Oct 22, 2026
9827ce5
style(rccl-ci): trim comments to the constraints they state
mkuznet1 Oct 22, 2026
19be2de
fix(rccl-ci): give the nodes back when the driver is interrupted
i-kosarev Oct 29, 2026
614ff32
ci(rccl): release the allocation from a step the runner itself starts
i-kosarev Oct 29, 2026
31d4b5d
fix(rccl-ci): kill the allocation's group even if scancel is interrupted
i-kosarev Oct 30, 2026
2e990a0
fix(rccl-ci): cancel a still-queued allocation, and never score stale…
i-kosarev Oct 30, 2026
a629835
feat(rccl-ci): score the A/B ratio against the previous run's ratio too
i-kosarev Oct 30, 2026
453c3ea
fix(rccl-ci): take only a passing run's ratio as the reference
i-kosarev Oct 30, 2026
c0e4d6d
fix(rccl-ci): key the previous-run reference on the base image too
i-kosarev Oct 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 70 additions & 26 deletions .github/workflows/therock-rccl-test-madengine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,26 @@ jobs:
exit 1
fi

- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'

# A venv on top of it: these runners are shared and long-lived, so anything
# installed straight into the interpreter would persist into the next job.
# This one lives under WORK_DIR and the cleanup step deletes it.
- name: Create Python virtual environment
# Conda-forge Python under WORK_DIR: the compute nodes (another distro, older
# glibc) run madengine from it via PATH, where setup-python's build won't start.
- name: Create Python environment
env:
MINIFORGE_VERSION: "26.7.2-0"
MINIFORGE_SHA256: "281b0ac7d550802efc81af633225a5e6116d29ae72f3ab4eae7168c3931a4c05"
run: |
# conda must write to $HOME, a small shared quota; redirect it into the
# conda prefix for this step only, so the nodes keep the real home.
export HOME="${WORK_DIR}/conda/home"
echo "PIP_CACHE_DIR=${HOME}/.cache/pip" >> "$GITHUB_ENV"
mkdir -p "${WORK_DIR}"
python3 -m venv "${WORK_DIR}/venv"
echo "${WORK_DIR}/venv/bin" >> "$GITHUB_PATH"
installer="${WORK_DIR}/Miniforge3.sh"
curl -fsSL -o "${installer}" \
"https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh"
echo "${MINIFORGE_SHA256} ${installer}" | sha256sum -c -
bash "${installer}" -b -p "${WORK_DIR}/conda"
rm -f "${installer}"
"${WORK_DIR}/conda/bin/conda" create -y -q -p "${WORK_DIR}/env" python=3.12
echo "${WORK_DIR}/env/bin" >> "$GITHUB_PATH"

# The datastore is only appended to at the very end of the workload, so
# an unwritable RESULTS_DIR would surface three hours in. A directory
Expand Down Expand Up @@ -163,13 +170,13 @@ jobs:
--output-dir="${OUTPUT_ARTIFACTS_DIR}" \
--rccl

# Both A/B phases in one allocation, plus its queue wait.
- name: Run MADEngine workload
timeout-minutes: 210
timeout-minutes: 360
env:
NCCL_DEBUG: WARN
MAD_SECRETS_HFTOKEN: ${{ secrets.HF_TOKEN || '' }}
run: |
source "${WORK_DIR}/venv/bin/activate"
export PYTHONPATH="rocm-systems/projects/rccl/ci/scripts:${PYTHONPATH}"

NOTIFY_ARGS=""
Expand All @@ -189,6 +196,33 @@ jobs:
--work-dir "${WORK_DIR}" \
$NOTIFY_ARGS

# Cancelling a run does not signal the driver: the runner kills this
# job's process tree outright and then reports "Terminate orphan
# process" for madengine and srun. No Python handler gets to run, and
# salloc holds the allocation in a session of its own, so the nodes stay
# taken until its --time expires -- four of them, for five hours, in the
# 405B case. Measured on run 40879865705: the job reached `cancelled`
# while SLURM job 104884 kept running with 4:48 left.
#
# The runner starts this step itself, which is what makes it the one
# piece of cleanup a cancellation cannot skip.
- name: Release the SLURM allocation
if: cancelled()
run: |
recorded="${WORK_DIR}/allocation.txt"
if [ ! -s "${recorded}" ]; then
echo "No allocation was granted; nothing to release."
exit 0
fi
job="$(head -n1 "${recorded}" | tr -d '[:space:]')"
case "${job}" in
''|*[!0-9]*)
echo "::warning::no usable job id in ${recorded}, got '${job}'"
exit 0 ;;
esac
echo "Releasing SLURM job ${job}"
scancel "${job}" || echo "::warning::scancel ${job} failed"

- name: Upload results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -198,22 +232,32 @@ jobs:
# nodes can only be read by someone with cluster access: the job log
# shows that SLURM failed, not why.
path: |
${{ env.WORK_DIR }}/perf.csv
${{ env.WORK_DIR }}/perf_entry_super.csv
${{ env.WORK_DIR }}/perf_entry_super.json
${{ env.WORK_DIR }}/perf_super.csv
${{ env.WORK_DIR }}/madengine_summary.txt
${{ env.WORK_DIR }}/manifest.json
${{ env.WORK_DIR }}/slurm_output/*.out
${{ env.WORK_DIR }}/slurm_output/*.err
${{ env.WORK_DIR }}/ab/*/perf.csv
${{ env.WORK_DIR }}/ab/*/perf_entry_super.csv
${{ env.WORK_DIR }}/ab/*/perf_entry_super.json
${{ env.WORK_DIR }}/ab/*/perf_super.csv
${{ env.WORK_DIR }}/ab/*/manifest.json
${{ env.WORK_DIR }}/ab/*/slurm_output/*.out
${{ env.WORK_DIR }}/ab/*/slurm_output/*.err
retention-days: 30

- name: Cleanup work directory
if: always()
run: |
# node_venv is the per-node bootstrap: on a single-node run the template
# puts WORKSPACE on the shared filesystem, so it lands here rather than
# in node-local storage and would otherwise outlive the run.
rm -rf "${WORK_DIR}/madengine" "${WORK_DIR}/MAD" "${WORK_DIR}/venv" \
"${WORK_DIR}/node_venv" "${WORK_DIR}/overlay_ctx" \
"${WORK_DIR}/docker_builds"
# `ab` holds the per-node logs, the only part that grows with the run;
# the upload step above has already kept them as an artifact.
rm -rf "${WORK_DIR}/madengine" "${WORK_DIR}/MAD" "${WORK_DIR}/conda" \
"${WORK_DIR}/env" "${WORK_DIR}/overlay_ctx" \
Comment thread
mkuznet1 marked this conversation as resolved.
Resolved
"${WORK_DIR}/docker_builds" "${WORK_DIR}/ab"

# Remove per-run tags and bases left by earlier versions of this job on
# the shared Docker disk; no -f, so images a container still uses stay.
docker system df || true
{
docker images --format '{{.Repository}}:{{.Tag}}' \
| grep -E -- '-(rccl-gfx[0-9a-z]+|primus-v[0-9.]+|mad-[0-9a-f]{8})-' || true
python3 -c 'import sys; sys.path.insert(0, sys.argv[1]); import test_madengine as t; print(*sorted({c["base_image"] for c in t.WORKLOAD_CONFIGS.values()}), sep="\n")' \
rocm-systems/projects/rccl/ci/scripts
} | sort -u | xargs -r docker image rm 2>&1 | grep -v 'No such image' || true
docker system df || true
Loading
Loading