ci(e2e): add e2e-gpu-rad3 lane for the scale-to-zero R9700 runner - #278
Conversation
35f40f8 to
eef5d7a
Compare
e5d2f1f to
9e33878
Compare
19920ac to
756c0f9
Compare
The rad3 cluster now has a self-hosted runner that KEDA scales 0<->1 off the GitHub job queue, so its Radeon AI PRO R9700S is reserved only while a job is running rather than around the clock (silogen/dev-tooling EAI-8065). This adds the lane that targets it. Modelled on e2e-gpu, with three differences: - runs-on [self-hosted, linux, r9700]. The label names the hardware instead of reusing amd-gpu, because GitHub matches label supersets: a shared generic label would let this 32GB card pick up MI300X-sized work and OOM. - E2E_SHARED_UV_CACHE_DIR is pinned to /var/tmp/rocm-e2e-uv-cache, which is a separate PVC in the rad3 overlay, kept off the work PVC. - The lane is dispatch-only and excluded from platform=all. A job queued on an offline self-hosted runner cannot be cancelled by GitHub, and a scale-to-zero runner is meant to have no pod most of the time, so an automatic trigger turns any cluster-side misconfiguration into runs that hang to the job cap. Separately, this repo is public, so wiring the lane to pull_request would let a fork PR run arbitrary code on a GPU node with cluster pull secrets and caches that persist between jobs -- a fork-approval policy decision that should be made explicitly rather than assumed here. Both restrictions are one-line changes once the runner has a track record. Non-blocking (continue-on-error) like the other new-hardware lanes, and added to e2e-report's needs so it appears in the consolidated grid. Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
…ed lanes The rad3 R9700 lane was dispatch-only (platform=rad3), excluded from platform=all and from the automatic push/PR/merge_queue triggers, while its runner was being brought up. The scale-to-zero runner is now validated end to end against real rocm-cli CI, so bring the lane in line with e2e-gpu and the strix lanes: automatic on push/PR/merge_queue when the serve set changed, plus dispatch for platform=all or platform=rad3. It stays continue-on-error, so it is non-blocking. Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
The e2e-gpu-rad3 lane uploads an `e2e-gpu-rad3-report` artifact, but nothing mapped it to a platform: parse_descriptor fell through to the titlecased fallback, and two xtask guards failed — one requiring every uploaded e2e artifact to be report-mappable, the other requiring the nightly lanes to publish the same platforms as the per-PR lanes. - map `gpu-rad3` -> (R9700, Linux) in parse_descriptor, and the runtime `gfx1201` slug -> e2e-gpu-rad3-report in label_for_root_report - add e2e-gpu-rad3-report to CANONICAL_REPORT_ARTIFACTS and both label tests - add a matching e2e-gpu-nightly-rad3 lane to nightly.yml so the per-PR and nightly platform sets agree Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
756c0f9 to
80e6819
Compare
The lane's header still described it as dispatch-only and excluded from platform=all, which stopped being true when it moved to the same triggers as the other self-hosted lanes. Drop that block and the fork-PR aside (a repo-wide concern, not this lane's to document), and shorten the label/gating comments to match the sibling lanes. Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
ReviewNice lane — the Blocking1. The canonical artifact list is now self-contradictory, and a guard test cements the wrong side.
So the repo states two different canonical lists, each pinned by a test — and the test actively blocks the fix, because adding rad3 to the doc list turns Suggested doc row: | `e2e-gpu-rad3` | `e2e-selfhosted.yml` | Radeon AI PRO R9700 (gfx1201) on Linux | self-hosted `[self-hosted, linux, r9700]` |…plus Worth a follow-up regardless: that test only compares the docs against themselves — it never reads 2.
E2E_MERGE_QUEUE: "${{ github.event_name == 'merge_group' && '1' || '' }}"( If it's deliberate, could you note it in the comment and in the difference table? Right now it reads as a dropped line. Worth an explicit decision
The rationale for dropping it is reasonable — Non-blocking
On duplication — not this PR's problem, but this PR is a good prompt for itMeasured across the 10 e2e lanes in To be clear, this PR isn't the offender — the two new lanes sit at 56%/68%, right at the existing norm, and that 97% identity with For a follow-up, the shape I'd suggest is a composite action, not a matrix:
Note that "one or two jobs" isn't reachable: Tracked separately in #294 so it doesn't block you here. Things done well
One note: the self-hosted lanes are Branch is 3 commits behind |
…arm check The rad3 lane was missing E2E_MERGE_QUEUE, so it ran the cheap PR canary at the merge-queue gate while every other platform got the full serve matrix — add it to match the siblings. Restore the post-install runtime-registry check the nightly rad3 lane had dropped (it was templated from the file-neighbour rather than the per-PR rad3 lane), so a silent pre-warm failure still prints. Reword the two uv-cache PVC path comments to be self-contained rather than pointing at an overlay path that lives in another repo. Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
The report code and its unit guards already knew about e2e-gpu-rad3, but the doc-contract layer did not, so the repo asserted two different canonical lists — and workflow_contract.rs pinned the wrong one, turning the doc fix red. Add the rad3 row to the job table, the r9700 dispatch option, and e2e-gpu-rad3-report to the canonical artifact list; drop the hardcoded "four" counts (docs + README) so the next platform doesn't reopen this; and update the contract assertions to match, renaming the test off the platform count. Signed-off-by: Tomas Saaristola <tsaarist@amd.com>
|
Thanks — thorough review, and the report/contract gap was a real miss. Addressed in Blocking — both fixed1. Self-contradictory canonical list. The report code + its unit guards knew about
2. Missing Non-blocking — fixed
Non-blocking — kept as-is (with reasoning)
Fork-approval policy — deferringI can't check the "Require approval for fork pull requests" setting (no admin). Since Re: the unexercised automatic-trigger path — agreed, will do one dispatch on a serve-touching branch around merge to exercise it. |
r0x0r
left a comment
There was a problem hiding this comment.
Approving. This adds a fifth self-hosted E2E lane for the rad3 R9700 (gfx1201) across both the per-PR (e2e-selfhosted.yml) and nightly (nightly.yml) workflows, and it faithfully mirrors the established lane structure rather than inventing a new one: same reclaim -> GPU-preflight -> prewarm -> cargo xtask e2e shape as e2e-gpu, same serve/dispatch if: gating, continue-on-error: true, and the existing include_nightly / E2E_MERGE_QUEUE wiring.
The [self-hosted, linux, r9700] label choice is correct — GitHub matches a job to any runner whose labels are a superset of the job's, so a distinct hardware label is what stops this card from picking up MI300X-targeted work; it follows the strix convention.
Crucially the naming contract stays green end to end: the new e2e-gpu-rad3-report artifact is threaded through parse_descriptor (gpu-rad3 -> R9700/Linux), the gfx1201 slug mapping and CANONICAL_REPORT_ARTIFACTS in xtask, and the docs-contract test in workflow_contract.rs. I verified there are no stale "four self-hosted/nightly platforms" references left behind — every occurrence is rewritten in lockstep. Third-party actions are pinned to full SHAs with version comments.
Two non-blocking notes: (1) the one red check, E2E tests (Strix Halo, Windows), is on a lane this PR does not touch and is continue-on-error, so it cannot gate the merge — reads as the known pre-existing Strix-Windows flake; please confirm. (2) The reclaim/preflight/prewarm block is now duplicated a fifth time; pre-existing debt this PR merely follows, but the file is at the size where a composite action would pay off (fine as a follow-up). Everything else is green.
What
Adds
e2e-gpu-rad3toe2e-selfhosted.yml, targeting a self-hosted runner on the rad3 cluster (Radeon AI PRO R9700S, gfx1201, 32GB).The runner is a Kubernetes pod that KEDA scales
0<->1off the GitHub job queue, so the card is reserved only while a job exists rather than around the clock — that's the point of the exercise (silogen/dev-tooling EAI-8065). The runner side is deployed fromsilogen/dev-tooling; this PR is only the workflow lane that uses it.How it differs from
e2e-gpuruns-on[self-hosted, linux, r9700]/var/tmp/rocm-e2e-uv-cache(a separate PVC in the rad3 overlay, kept off the work PVC)Triggers and gating are identical to the other self-hosted lanes: automatic on push/PR/merge_queue when the serve set changed, and on dispatch for
platform=allorplatform=rad3.continue-on-error: true, like the rest, so a rad3 flake never blocks a PR.The label names the hardware (
r9700) rather than reusingamd-gpu, because GitHub assigns a job to any runner whose label set is a superset of the job's. Distinct per-hardware labels keep the pools separately addressable — the same convention the strix lanes already follow — so rad3 only picks up work aimed at it, not MI300X-targeted jobs.Scale-to-zero, and why it's transparent to CI
The runner has no pod most of the time. A queued job is what wakes it: KEDA sees the job, scales the StatefulSet
0->1, the pod connects within a poll interval, runs the job, and scales back to0after a cooldown. From the workflow's side this is just a self-hosted runner that happens to have startup latency; no lane logic depends on it.The one operational caveat is generic to self-hosted runners, not specific to scale-to-zero: a job queued while a runner is offline can't be cancelled by GitHub until a runner connects. Scale-to-zero makes "no pod" the normal state, so the mitigation that matters is a health alert on the ScaledObject (tracked in EAI-8150) — a dead scaler is the only way the wake never happens. The older concurrency-starvation footgun (PR #138) is already handled by this workflow having its own concurrency group.
Testing
Validated end to end against the real
ROCm/rocm-cliCI on the rad3 R9700, viaworkflow_dispatchwith a single-scenarioname_filter:Active=Truewithin one 30s poll0->1, pod admitted withamd.com/gpu: 1,Runningin ~28s (warm node)E2E tests (rad3 R9700)completed Succeeded (examinescenario 3, GPU + driver detection — a real GPU check)Active=False,cooldownPeriod: 300held the pod, then scaled1->0; pod gone, GPU released, no stranded pod and no manual cleanupEarlier bring-up against a private scratch repo also exercised a job longer than
cooldownPeriod(ran to completion untouched) and a cancelled job (released on the same path).Risk
Low. The lane is
continue-on-error, so it can't block merges, and it mirrors the established self-hosted lane structure. Fork-PR execution on self-hosted runners in this public repo is a repo-wide consideration that already applies to the app-dev and strix lanes; it is not specific to this one.