Skip to content

ci: run build-wheel and radix-tree benchmark on the CPU runner; let CPU runners use GPU-node CPU - #1730

Merged
slin1237 merged 4 commits into
mainfrom
ci/build-wheel-cpu-runner
Jun 15, 2026
Merged

slin1237 merged 4 commits into
mainfrom
ci/build-wheel-cpu-runner

Conversation

@slin1237

@slin1237 slin1237 commented Jun 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Moves CPU-only jobs off the GPU runner pool and lets the CPU runner use GPU-node CPU.

The problem (from a live cluster check): build-wheel and the radix-tree benchmark are pure compiles/benchmarks — no GPU at build or runtime — but ran on runs-on: k8s-runner-gpu. That label is currently served by a runner pool pinned to BM.GPU.A10.4 nodes, whose A10 GPUs are fully consumed by other (VLA/robobrain) workloads, so the runner pods sat Pending for 60–90 min and jobs reported "no runner" — even though the cluster had ~2,600 idle CPU cores on GPU nodes (GPUs get exhausted while CPUs strand).

Changes

  1. build-wheel → k8s-runner-cpu (pr-test-rust.yml) — Rust workspace + Python wheel + Go FFI + WASM compile, no GPU.
  2. benchmark-radix-tree → k8s-runner-cpu (benchmark-radix-tree.yml) — cargo bench on the kv-index radix tree / throughput suites, CPU-only.
  3. CPU runner tolerates the nvidia.com/gpu taint (runner-values-cpu.yaml, operator: Exists) so it can also schedule onto GPU nodes' stranded CPU. No nodeSelector (still runs on plain CPU nodes); robobrain / robobrain-vla / ci-runner taints are deliberately not tolerated.

To apply the runner change

The runner-values-cpu.yaml edit needs a Helm upgrade — the repo manifests aren't auto-reconciled to the cluster (live scale sets are already drifted from these files):

helm upgrade k8s-runner-cpu -n actions-runner-system \
  -f scripts/k8s-runner-resources/runner-values-cpu.yaml \
  oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set

The runs-on workflow changes take effect on merge regardless (they route to the existing CPU runners, which already run on the CPU node pool).

Caveat / live test

The CPU runner is 8 CPU / 16Gi, down from 32 CPU / 128Gi that build-wheel got on the GPU runner. This PR's own build-wheel run executes on k8s-runner-cpu — watch its build time and for OOM. If 16Gi is too tight for a from-scratch workspace compile, the easy follow-up is bumping just the runner memory; kept at 8c/16Gi per the decision to start small.

Not touched (separate review)

nightly-benchmark.yml and the disabled go-bindings-benchmark job still target k8s-runner-gpu; the nightly benchmark may legitimately want GPU.

Summary by CodeRabbit

  • Chores
    • Updated CI workflows to run Rust wheel builds and Radix Tree benchmarks on CPU-only runner pools instead of GPU runners.
    • Adjusted the CPU runner Kubernetes pod template tolerations so CPU runners can be scheduled onto nodes marked with GPU-related taints, while avoiding unrelated taints to preserve existing scheduling behavior.

build-wheel is a CPU-only compile (Rust workspace + Python wheel + Go FFI
+ WASM fixtures) but ran on `k8s-runner-gpu`. That label is currently
served by a wedged runner pool pinned to BM.GPU.A10.4 nodes, whose GPUs
are fully consumed by other workloads — so the job queued with 'no
runner' even though the cluster had ~2600 idle GPU-node CPU cores.

- Move build-wheel to `runs-on: k8s-runner-cpu`. It no longer competes
  for scarce GPU runners.
- Add an `nvidia.com/gpu` toleration (operator: Exists) to the CPU
  runner so it can also schedule onto GPU nodes' stranded CPU. No
  nodeSelector, so it still runs on plain CPU nodes; robobrain /
  robobrain-vla / ci-runner taints are deliberately NOT tolerated.

Note: the runner-values change requires `helm upgrade k8s-runner-cpu -f
scripts/k8s-runner-resources/runner-values-cpu.yaml` to apply — the repo
manifests are not auto-reconciled to the cluster. The build-wheel runner
stays 8 CPU / 16Gi (down from 32 CPU / 128Gi on the GPU runner); this
PR's own build-wheel run on the CPU pool is the live check for fit.

Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@github-actions github-actions Bot added the ci CI/CD configuration changes label Jun 15, 2026
@coderabbitai

coderabbitai Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@slin1237, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 hour, 27 minutes, and 25 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97bbbd75-7731-4cd7-8802-4d55a47845e3

📥 Commits

Reviewing files that changed from the base of the PR and between 846d292 and ff1a0f2.

📒 Files selected for processing (2)
  • .github/actions/setup-rust/action.yml
  • .github/workflows/pr-test-rust.yml
📝 Walkthrough

Walkthrough

The build-wheel and benchmark-radix-tree CI jobs are switched from the GPU runner pool (k8s-runner-gpu) to the CPU runner pool (k8s-runner-cpu). To enable CPU runners to utilize CPU capacity on GPU-tainted nodes, a tolerations section is added to the CPU runner pod spec allowing scheduling on nodes with the nvidia.com/gpu:NoSchedule taint.

Changes

CPU Runner Scheduling for build-wheel and Benchmark

Layer / File(s) Summary
CPU runner GPU-node toleration
scripts/k8s-runner-resources/runner-values-cpu.yaml
Adds template.spec.tolerations with nvidia.com/gpu Exists/NoSchedule toleration so CPU runner pods may schedule on GPU-tainted nodes using their stranded CPU capacity.
Workflow jobs switched to CPU runners
.github/workflows/pr-test-rust.yml, .github/workflows/benchmark-radix-tree.yml
Changes the build-wheel and benchmark-radix-tree jobs' runs-on labels from k8s-runner-gpu to k8s-runner-cpu, with inline comments clarifying CPU-only compilation for Rust/wheel/Go-FFI/WASM and CPU-only criterion/throughput benchmarking.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Suggested labels

ci

Possibly related PRs

  • lightseekorg/smg#1372: Modifies GitHub Actions workflow runs-on labels to switch builds from GPU runners to CPU runners for docker workflows.
  • lightseekorg/smg#357: Directly modifies .github/workflows/pr-test-rust.yml to change how jobs select Kubernetes runner types (CPU vs GPU/H100).

Suggested reviewers

  • CatherineSue
  • key4ng

Poem

🐇 Hoppity-hop, no GPU in sight,
The wheel and benchmark now run on CPU's might!
Tolerations added, the pods can roam free,
On GPU-tainted nodes — just CPU, you see.
Less wasted resource, more efficient the way,
The rabbit approves! Hip hip, hooray! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: moving build-wheel and radix-tree benchmark jobs to CPU runner, plus enabling CPU runners to use GPU-node CPU capacity via tolerations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/build-wheel-cpu-runner

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds tolerations to runner-values-cpu.yaml to allow CPU runners to schedule on GPU nodes with the nvidia.com/gpu taint, utilizing idle CPU capacity. The reviewer recommends adding a preferred node affinity to bias scheduling toward plain CPU nodes first, preventing potential resource fragmentation or starvation on GPU nodes. Additionally, they suggest applying these changes consistently to arc-runner-cpu.yaml.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +28 to +31
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While tolerating the nvidia.com/gpu taint allows CPU runners to utilize idle CPU capacity on GPU nodes, without a soft node affinity, the Kubernetes scheduler might schedule these CPU-only runners on GPU nodes even when plain CPU nodes have ample capacity. This can lead to CPU/memory fragmentation or starvation on GPU nodes, potentially blocking expensive GPU workloads from scheduling.

To prevent this, it is highly recommended to add a preferred node affinity that biases the scheduler toward plain CPU nodes first, only falling back to GPU nodes when CPU nodes are fully utilized.

Additionally, to maintain consistency across all deployment paths, the same tolerations and affinity should be applied to the alternative CPU runner deployment in scripts/k8s-runner-resources/arc-runner-cpu.yaml.

    tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
    affinity:
      nodeAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
                - key: "nvidia.com/gpu"
                  operator: "DoesNotExist"
References
  1. To maintain consistency, changes to a feature on one execution path should align with its behavior on related paths.

The radix-tree benchmark only runs `cargo bench` on the kv-index radix
tree and throughput suites — pure CPU, no GPU. Move it off
`k8s-runner-gpu` onto `k8s-runner-cpu` like build-wheel, so it doesn't
queue behind GPU-runner contention.

Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@claude

claude Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

👋 The PR description doesn't fully follow
PULL_REQUEST_TEMPLATE.md:

  • Missing header: ## Description
  • Missing header: ### Problem
  • Missing header: ### Solution
  • Missing header: ## Test Plan

Please update the PR description so reviewers have the context they need.

@slin1237 slin1237 changed the title ci: run build-wheel on the CPU runner; let CPU runners use GPU-node CPU ci: run build-wheel and radix-tree benchmark on the CPU runner; let CPU runners use GPU-node CPU Jun 15, 2026
…rget dir

The build-wheel job was slow on every code PR because its caching was
ineffective:

- The actions/cache 'wheel and Go FFI artifacts' step was keyed on a
  hash of every crate's source, so it missed on essentially any PR that
  touches Rust (all-or-nothing). Worse, on a miss it skipped the build
  via 'if: cache-hit != true', which masked the incremental compilation
  cache (rust-cache + sccache) and meant rust-cache rarely got saved.
- The Go FFI build (bindings/golang/Makefile) overrides CARGO_TARGET_DIR
  to bindings/golang/target, which Swatinem rust-cache's 'workspaces: .'
  never covered — so the Go FFI's dependency compilation was never
  cached across runs at all.

Changes:
- Remove the wheel-output cache step and the cache-hit guards; the build
  now always runs and relies on rust-cache + sccache, which degrade
  gracefully — with the dependency graph cached, only changed crates
  recompile.
- Add bindings/golang/target to rust-cache's cache-directories so the Go
  FFI build is incremental across runs like the wheel build.

Note: the wheel stays manylinux 2_28 + vendored-openssl (portability is
required — the cluster has glibc-2.28 nodes), and maturin's --zig
cross-compile keeps the wheel and Go FFI on separate toolchains, so this
targets cross-run caching rather than within-run dedup. Trade-off:
no-Rust PRs lose the ~34s build skip in favor of a fast incremental
build, while code PRs (the common case) drop from a full ~8-23m build to
an incremental one.

Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0fbc14c64

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

# CPU-only criterion/throughput benchmarks of the kv-index radix tree —
# no GPU needed, so it runs on the CPU runner pool rather than competing
# for GPU runners.
runs-on: k8s-runner-cpu

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve CPU capacity for radix benchmarks

When this workflow runs its scheduled/PR performance benchmarks, switching from k8s-runner-gpu to k8s-runner-cpu also switches hardware: the repo’s k8s-runner-gpu values request 32 CPUs/128Gi, while k8s-runner-cpu requests only 8 CPUs/16Gi. The criterion/throughput jobs here are CPU-bound (including the 256-worker throughput run below), so the reported artifacts become dominated by the smaller runner and are not comparable with prior runs. Please use a CPU runner label with equivalent dedicated resources, or adjust/rename the benchmark to make the new baseline explicit.

Useful? React with 👍 / 👎.

No-op commit to produce a second build-wheel run that restores the
rust-cache saved by the previous (cold) run, demonstrating the
incremental build time. Can be squashed/dropped before merge.

Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@slin1237
slin1237 merged commit 7723a4f into main Jun 15, 2026
30 of 38 checks passed
@slin1237
slin1237 deleted the ci/build-wheel-cpu-runner branch June 15, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD configuration changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant