Skip to content

Commit fac41e4

Browse files
committed
Migrate perf-gate CI image flow to nvcr.io
Move the perf-gate's prebuilt-image flow off GHCR and onto the shared NGC registry (nvcr.io), the same registry the rest of IsaacLab CI uses. - Default the gate and seeder to nvcr.io/nvidian/isaac-lab:latest-perf, with PERF_GATE_CI_IMAGE as an optional override; drop the GHCR login and packages permission. The gate keeps a build-from-source fallback; seeding fails fast if the image is missing. - Overlay the PR checkout over a pulled env image so the benchmark runs the PR's code, not the image's baked source. - Publish dual tags (latest-perf plus an immutable sha-<short>) so a past era stays pinnable. Note: the baseline-independence and block-floor changes are intentionally left out pending root-cause analysis of the regression-magnitude question.
1 parent 6c76e4a commit fac41e4

3 files changed

Lines changed: 122 additions & 77 deletions

File tree

.github/workflows/perf-gate-publish-image.yaml

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55

66
# Perf Gate — Publish CI Image
77
#
8-
# Builds docker/Dockerfile.base once and publishes it to a container registry so the
9-
# Performance Regression Gate can pull a prebuilt image instead of cold-building it on
10-
# every matrix cell. This is the temporary fast path while the NVIDIA-managed RTX PRO
11-
# 6000 fleet has no provisioned ECR/registry cache.
8+
# Builds docker/Dockerfile.base once and publishes it to NGC (nvcr.io) so the
9+
# Performance Regression Gate (and the baseline seeder) can pull one prebuilt image
10+
# instead of cold-building it on every matrix cell. nvcr.io is the same registry the
11+
# rest of IsaacLab CI uses (the post-merge job pushes nvcr.io/nvidian/isaac-lab:latest-*)
12+
# and is reachable from the NVIDIA-managed RTX PRO 6000 fleet, so this is the standard
13+
# distribution path — not a one-off. ECR on that fleet is only a local build-layer cache.
1214
#
1315
# Usage:
1416
# 1. Run this workflow (Actions tab → "Perf Gate — Publish CI Image" → Run workflow).
15-
# Default target is GHCR: ghcr.io/<owner>/isaaclab-perf-gate:<tag>. To use
16-
# NGC/NVCR instead, set the `registry` input to an nvcr.io/... path.
17-
# 2. Set the repo variable PERF_GATE_CI_IMAGE to the full pushed reference printed in
18-
# the job summary (e.g. ghcr.io/<owner>/isaaclab-perf-gate:sha-abcdef1).
17+
# Default target is nvcr.io/nvidian/isaac-lab:latest-perf. Override the `registry`
18+
# / `tag` inputs to publish elsewhere (e.g. an immutable sha-<short> tag).
19+
# 2. Nothing else is required for the default tag: the gate and seeder already pull
20+
# nvcr.io/nvidian/isaac-lab:latest-perf by default. Only set the repo variable
21+
# PERF_GATE_CI_IMAGE if you published to a non-default repo/tag and want them to use it.
1922
# 3. Re-run whenever docker/Dockerfile.base or the pinned dependencies change.
2023
#
2124
# Runs on the same RTX fleet label as the gate: the build needs nvcr.io access for the
@@ -29,7 +32,7 @@ on:
2932
# exposes the "Run workflow" button for workflows already on the default branch, which
3033
# this is not yet. Scoped with paths so ordinary code pushes don't kick off a ~26 min
3134
# rebuild — only image-affecting changes do. A push event has no inputs, so the job
32-
# falls back to its defaults (GHCR target, sha-<short> tag).
35+
# falls back to its defaults (nvcr.io/nvidian/isaac-lab:latest-perf).
3336
# Remove this push trigger once the workflow lands on develop and dispatch is available.
3437
push:
3538
branches: [unified-POC]
@@ -40,17 +43,16 @@ on:
4043
workflow_dispatch:
4144
inputs:
4245
registry:
43-
description: 'Target image repository (no tag). Default GHCR; use nvcr.io/... for NGC.'
46+
description: 'Target image repository (no tag). Default nvcr.io/nvidian/isaac-lab.'
4447
required: false
4548
default: ''
4649
tag:
47-
description: 'Image tag to publish. Defaults to sha-<short-sha>.'
50+
description: 'Image tag to publish. Defaults to latest-perf.'
4851
required: false
4952
default: ''
5053

5154
permissions:
5255
contents: read
53-
packages: write # push to GHCR under this repository's owner
5456

5557
env:
5658
# Lets the build log into nvcr.io to pull the Isaac Sim base image.
@@ -77,20 +79,33 @@ jobs:
7779
echo "isaacsim_image_name=${IMG}" >> "$GITHUB_OUTPUT"
7880
echo "isaacsim_image_tag=${TAG}" >> "$GITHUB_OUTPUT"
7981
80-
# Default target repo: GHCR under this repo's owner (lowercased, as GHCR requires).
81-
OWNER="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
82+
# Default target repo: the shared IsaacLab NGC repo (reachable from the RTX fleet,
83+
# same registry the post-merge job publishes to). Override via the `registry` input.
8284
TARGET_REPO="${{ inputs.registry }}"
8385
if [ -z "${TARGET_REPO}" ]; then
84-
TARGET_REPO="ghcr.io/${OWNER}/isaaclab-perf-gate"
86+
TARGET_REPO="${{ vars.PERF_GATE_PUBLISH_REPO || 'nvcr.io/nvidian/isaac-lab' }}"
8587
fi
8688
89+
# Default tag: a stable, human-friendly tag (mirrors IsaacLab's latest-develop).
90+
# Pass `tag: sha-<short>` for an immutable, reproducible reference.
8791
TARGET_TAG="${{ inputs.tag }}"
8892
if [ -z "${TARGET_TAG}" ]; then
89-
TARGET_TAG="sha-${GITHUB_SHA::7}"
93+
TARGET_TAG="latest-perf"
9094
fi
9195
96+
# Always also publish an immutable sha-<short> tag so a past era stays pinnable
97+
# (the moving tag above is overwritten each publish). Mirrors IsaacLab pushing
98+
# both latest-develop and latest-develop-<sha>. Skipped only when the chosen tag
99+
# already IS the immutable one.
100+
IMMUTABLE_TAG="sha-${GITHUB_SHA::7}"
92101
echo "target_image=${TARGET_REPO}:${TARGET_TAG}" >> "$GITHUB_OUTPUT"
93-
echo "🔵 Will publish: ${TARGET_REPO}:${TARGET_TAG}"
102+
if [ "${TARGET_TAG}" != "${IMMUTABLE_TAG}" ]; then
103+
echo "target_image_immutable=${TARGET_REPO}:${IMMUTABLE_TAG}" >> "$GITHUB_OUTPUT"
104+
echo "🔵 Will publish: ${TARGET_REPO}:${TARGET_TAG} + ${TARGET_REPO}:${IMMUTABLE_TAG}"
105+
else
106+
echo "target_image_immutable=" >> "$GITHUB_OUTPUT"
107+
echo "🔵 Will publish: ${TARGET_REPO}:${TARGET_TAG}"
108+
fi
94109
95110
# Build (or reuse the gha layer cache for) the image locally, tagged perf-gate-publish:local.
96111
- name: Build CI image
@@ -108,6 +123,7 @@ jobs:
108123
- name: Push image to target registry
109124
env:
110125
TARGET_IMAGE: ${{ steps.cfg.outputs.target_image }}
126+
TARGET_IMAGE_IMMUTABLE: ${{ steps.cfg.outputs.target_image_immutable }}
111127
run: |
112128
set -euo pipefail
113129
@@ -118,10 +134,6 @@ jobs:
118134
119135
REGISTRY="${TARGET_IMAGE%%/*}"
120136
case "${REGISTRY}" in
121-
ghcr.io)
122-
echo "🔵 Logging into ghcr.io..."
123-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
124-
;;
125137
nvcr.io)
126138
if [ -z "${NGC_API_KEY:-}" ]; then
127139
echo "::error::NGC_API_KEY is required to push to nvcr.io"
@@ -131,22 +143,29 @@ jobs:
131143
echo "${NGC_API_KEY}" | docker login nvcr.io -u '$oauthtoken' --password-stdin
132144
;;
133145
*)
134-
echo "::error::Unsupported target registry '${REGISTRY}'. Use ghcr.io or nvcr.io."
146+
echo "::error::Unsupported target registry '${REGISTRY}'. The perf gate publishes to nvcr.io."
135147
exit 1
136148
;;
137149
esac
138150
139-
docker tag perf-gate-publish:local "${TARGET_IMAGE}"
140-
echo "🔵 Pushing ${TARGET_IMAGE}..."
141-
docker push "${TARGET_IMAGE}"
151+
# Push the (moving) primary tag and, when distinct, the immutable sha tag.
152+
PUSHED=()
153+
for IMG in "${TARGET_IMAGE}" "${TARGET_IMAGE_IMMUTABLE}"; do
154+
[ -z "${IMG}" ] && continue
155+
docker tag perf-gate-publish:local "${IMG}"
156+
echo "🔵 Pushing ${IMG}..."
157+
docker push "${IMG}"
158+
PUSHED+=("${IMG}")
159+
done
142160
rm -rf "${DOCKER_CONFIG_DIR}"
143161
144162
{
145163
echo "## Published perf-gate CI image"
146164
echo ""
147165
echo '```'
148-
echo "${TARGET_IMAGE}"
166+
for IMG in "${PUSHED[@]}"; do echo "${IMG}"; done
149167
echo '```'
150168
echo ""
151-
echo "Set the repo variable \`PERF_GATE_CI_IMAGE\` to the value above so the gate pulls it instead of building."
169+
echo "The gate and seeder pull \`nvcr.io/nvidian/isaac-lab:latest-perf\` by default — no further action needed for that tag."
170+
echo "The immutable \`sha-<short>\` tag is for pinning a past era (e.g. bisection): set the repo variable \`PERF_GATE_CI_IMAGE\` to it when you need that exact environment."
152171
} >> "$GITHUB_STEP_SUMMARY"

.github/workflows/perf-gate-seed-baselines.yaml

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
# The samples are keyed by their real commit SHA, so the gate's merge-base /
1313
# ancestry isolation has a populated, branch-correct baseline to compare against.
1414
#
15-
# Requires the prebuilt-image fast path: set repo variable PERF_GATE_CI_IMAGE to
16-
# the published CI image (GHCR first, NGC/NVCR fallback). Without it there is no
17-
# image to source-mount into, and the job fails fast with a clear message.
15+
# Uses the prebuilt CI image published to nvcr.io (the same image the gate pulls, so
16+
# baselines and PR runs share an identical environment). Defaults to
17+
# nvcr.io/nvidian/isaac-lab:latest-perf; set repo variable PERF_GATE_CI_IMAGE only to
18+
# override that (e.g. to pin a sha-<short> tag). If the image is not published yet the
19+
# job fails fast with a clear message (publish it first via perf-gate-publish-image).
1820
#
1921
# Manual dispatch only — seeding writes to perf-baselines and burns GPU time, so
2022
# it should never run automatically.
@@ -69,7 +71,6 @@ concurrency:
6971

7072
permissions:
7173
contents: write # push appended samples to the perf-baselines branch
72-
packages: read # pull the prebuilt CI image from GHCR (PERF_GATE_CI_IMAGE)
7374

7475
env:
7576
NGC_API_KEY: ${{ secrets.NGC_API_KEY }}
@@ -111,17 +112,14 @@ jobs:
111112
git fetch --no-tags origin "+refs/heads/perf-baselines:refs/remotes/origin/perf-baselines" || \
112113
echo "::notice::perf-baselines not found yet; first seed run will create it"
113114
114-
- name: Require prebuilt CI image
115-
if: ${{ vars.PERF_GATE_CI_IMAGE == '' }}
116-
run: |
117-
echo "::error::PERF_GATE_CI_IMAGE is not set. Seeding source-mounts the published"
118-
echo "::error::CI image; publish one (perf-gate-publish-image) and set the variable."
119-
exit 1
120-
121-
# Pull the published CI image and retag it locally (mirrors the gate's override path).
115+
# Pull the published CI image and retag it locally (the exact image the gate pulls,
116+
# so seeded baselines and PR runs share one environment). Defaults to
117+
# nvcr.io/nvidian/isaac-lab:latest-perf; set PERF_GATE_CI_IMAGE to override (e.g. to
118+
# pin a sha-<short> tag). Unlike the gate there is no build fallback: seeding is a
119+
# deliberate, baseline-writing op, so a missing image should fail fast (publish first).
122120
- name: Pull prebuilt CI image
123121
env:
124-
OVERRIDE_IMAGE: ${{ vars.PERF_GATE_CI_IMAGE }}
122+
CI_IMAGE_REF: ${{ vars.PERF_GATE_CI_IMAGE || 'nvcr.io/nvidian/isaac-lab:latest-perf' }}
125123
run: |
126124
set -euo pipefail
127125
@@ -131,12 +129,8 @@ jobs:
131129
echo '{"credsStore":""}' > "${DOCKER_CONFIG_DIR}/config.json"
132130
export DOCKER_CONFIG="${DOCKER_CONFIG_DIR}"
133131
134-
REGISTRY="${OVERRIDE_IMAGE%%/*}"
132+
REGISTRY="${CI_IMAGE_REF%%/*}"
135133
case "${REGISTRY}" in
136-
ghcr.io)
137-
echo "🔵 Logging into ghcr.io..."
138-
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
139-
;;
140134
nvcr.io)
141135
if [ -n "${NGC_API_KEY:-}" ]; then
142136
echo "🔵 Logging into nvcr.io..."
@@ -150,10 +144,14 @@ jobs:
150144
;;
151145
esac
152146
153-
echo "🔵 Pulling prebuilt image ${OVERRIDE_IMAGE}..."
154-
docker pull "${OVERRIDE_IMAGE}"
155-
docker tag "${OVERRIDE_IMAGE}" "${{ env.CI_IMAGE_TAG }}"
156-
echo "🟢 Tagged ${OVERRIDE_IMAGE} as ${{ env.CI_IMAGE_TAG }}"
147+
echo "🔵 Pulling prebuilt image ${CI_IMAGE_REF}..."
148+
docker pull "${CI_IMAGE_REF}" || {
149+
echo "::error::Failed to pull ${CI_IMAGE_REF}. Publish it first via perf-gate-publish-image"
150+
echo "::error::(default tag latest-perf), or set PERF_GATE_CI_IMAGE to an existing image."
151+
exit 1
152+
}
153+
docker tag "${CI_IMAGE_REF}" "${{ env.CI_IMAGE_TAG }}"
154+
echo "🟢 Tagged ${CI_IMAGE_REF} as ${{ env.CI_IMAGE_TAG }}"
157155
rm -rf "${DOCKER_CONFIG_DIR}"
158156
159157
- name: Seed baselines from commit history

0 commit comments

Comments
 (0)