Skip to content

Commit da688e9

Browse files
authored
Make PrimeCaches the only Rust cache writer and remove sccache (#1963)
Makes PrimeCaches the only workflow that writes Rust caches, and removes sccache. PR CI hit sccache rate limits (429/503), and caches on main kept growing until they filled the 10 GB repository quota. rust-cache keeps every dependency version it restores, so entries saved after builds on restored caches grow with each lockfile change. * Remove sccache. The jobs it served (fuzz, non-PIE guests, bench baseline) get rust-cache entries. * PrimeCaches looks up each key and builds from a cold target only on a miss. Every other workflow restores only. * Scheduled, Miri and Copilot jobs no longer write caches. * A final PrimeCaches job deletes superseded `v1-rust-*` and `sysroot-*` entries on main. * Bump rust-cache to v2.9.3 and start under the `v1-rust` prefix, so the first run replaces the grown `v0-rust` entries. A cold PrimeCaches run on this branch saved about 8.6 GB in total. The largest entries are code-checks (1.4 GB Linux, 1.0 GB Windows) and the eight host entries (540–620 MB each). Follow-ups: caches for Miri X64, Windows arm64, macOS and trace fuzz guests. Easiest to review commit-by-commit --------- Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent d9b0320 commit da688e9

16 files changed

Lines changed: 305 additions & 167 deletions

‎.github/actions/setup-sccache/action.yml‎

Lines changed: 0 additions & 19 deletions
This file was deleted.

‎.github/workflows/CargoAudit.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
- uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2.0.0
2121
with:
2222
toolchain: "1.94"
23+
cache: false
2324

2425
- uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0
2526
with:

‎.github/workflows/Coverage.yml‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,6 @@ jobs:
4444
env:
4545
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4646

47-
- name: Rust cache
48-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
49-
with:
50-
shared-key: "${{ runner.os }}-debug"
51-
cache-on-failure: "true"
52-
# Only save on main as caches are not shared across branches.
53-
# https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache
54-
save-if: ${{ github.ref == 'refs/heads/main' }}
55-
56-
- name: Set up sccache
57-
uses: ./.github/actions/setup-sccache
58-
5947
- name: Build guest binaries
6048
run: just guests
6149

‎.github/workflows/PrimeCaches.yml‎

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
22

3-
# Builds on main to populate the GitHub Actions cache for all Swatinem/rust-cache
4-
# shared-keys used by PR workflows. Caches saved on `refs/heads/main` are
5-
# restorable from every PR via the base-branch fallback. PR workflows are
6-
# configured with `save-if: github.ref == 'refs/heads/main'`, so they only ever
7-
# read from this cache.
3+
# The only workflow that writes the Rust caches pull requests restore. Entries
4+
# saved on main are restorable from every pull request. Every other workflow
5+
# only reads them.
86
#
9-
# No tests are run here. The goal is just to populate dependency build artifacts
10-
# so that PR jobs start warm.
7+
# Each job looks up the entry for its current lockfiles and toolchain. If it
8+
# is missing, the job builds from a cold target and saves. rust-cache keeps
9+
# every dependency version it restores, so a build on a restored entry would
10+
# grow it with each lockfile change. Tests build but do not run.
11+
#
12+
# Keys hash lockfiles and toolchains, not build commands. Bump `prefix-key` in
13+
# every rust-cache step after changing what a job here builds.
1114

1215
name: Prime Caches
1316

@@ -16,6 +19,12 @@ on:
1619
branches: [main]
1720
workflow_dispatch:
1821

22+
# A new run replaces a pending one and never cancels the running one, so the
23+
# newest commit always saves.
24+
concurrency:
25+
group: prime-caches-${{ github.ref }}
26+
cancel-in-progress: false
27+
1928
env:
2029
CARGO_TERM_COLOR: always
2130
RUST_BACKTRACE: full
@@ -40,17 +49,31 @@ jobs:
4049
with:
4150
arch: ${{ matrix.arch }}
4251
config: ${{ matrix.config }}
52+
prime_cache: true
4353

44-
# Populate v0-rust-code-checks-{linux,windows} caches.
54+
# Populate v1-rust-code-checks-{linux,windows} caches.
4555
code-checks:
4656
uses: ./.github/workflows/dep_code_checks.yml
4757
secrets: inherit
58+
with:
59+
prime_cache: true
60+
61+
# Populate the fuzz cache (key fuzz-{arch}) with every fuzz target.
62+
fuzz:
63+
uses: ./.github/workflows/dep_fuzzing.yml
64+
secrets: inherit
65+
with:
66+
prime_cache: true
67+
arch: X64
68+
target: all
69+
max_total_time: 0
70+
timeout_minutes: 30
4871

4972
# Populate the host caches (key {arch}-{os}-{hypervisor}-{config}) used by
5073
# dep_build_test.yml. Linux is primed once per hypervisor because the kvm
5174
# pools run Ubuntu and the mshv3 pools run Azure Linux 3, and we want each
52-
# distro to restore a cache produced under its own libc. Only the host
53-
# dependency graph is built here, no tests are run.
75+
# distro to restore a cache produced under its own libc. The host, its tests
76+
# and hyperlight-ci are built here. No tests run.
5477
host:
5578
strategy:
5679
fail-fast: false
@@ -102,17 +125,44 @@ jobs:
102125
env:
103126
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
104127

128+
# Keep the steps before this one in sync with dep_build_test.yml. The key
129+
# hashes the installed toolchains and the Rust and C build env vars.
105130
- name: Rust cache
106-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
131+
id: rust-cache
132+
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
107133
with:
134+
prefix-key: v1-rust
108135
shared-key: "${{ matrix.arch }}-${{ runner.os }}-${{ matrix.hypervisor }}-${{ matrix.config }}"
109-
cache-on-failure: "true"
110-
# Only save on main as caches are not shared across branches.
111-
# https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache
112-
save-if: ${{ github.ref == 'refs/heads/main' }}
136+
lookup-only: true
113137

114-
- name: Set up sccache
115-
uses: ./.github/actions/setup-sccache
138+
- name: Build host and tests
139+
if: steps.rust-cache.outputs.cache-hit != 'true'
140+
run: just prime-caches ${{ matrix.config }}
116141

117-
- name: Build host
118-
run: just build ${{ matrix.config }}
142+
# Rust keys end in a toolchain hash and a lockfile hash. Sysroot keys end in
143+
# one hash. Each change leaves the old entry behind. Keep the newest entry
144+
# per key and delete the rest to stay under the repository cache quota.
145+
cleanup:
146+
needs: [guests, code-checks, fuzz, host]
147+
if: ${{ !cancelled() }}
148+
runs-on: ubuntu-latest
149+
permissions:
150+
actions: write
151+
env:
152+
GH_TOKEN: ${{ github.token }}
153+
GH_REPO: ${{ github.repository }}
154+
steps:
155+
- name: Delete superseded caches
156+
run: |
157+
# Filter by key prefix. The listing caps at 1000 entries.
158+
for prefix in v1-rust- sysroot-; do
159+
gh cache list --ref "$GITHUB_REF" --key "$prefix" --limit 1000 --json id,key,createdAt
160+
done | jq -s -r '
161+
add
162+
| group_by(.key | if startswith("sysroot-") then sub("-[^-]*$"; "") else sub("-[^-]*-[^-]*$"; "") end)
163+
| map(sort_by(.createdAt) | reverse | .[1:][])
164+
| .[] | "\(.id) \(.key)"' |
165+
while read -r id key; do
166+
echo "Deleting $key"
167+
gh cache delete "$id" || echo "::warning::Failed to delete $key"
168+
done

‎.github/workflows/RustNightly.yml‎

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,6 @@ jobs:
5050
env:
5151
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5252

53-
# cargo-hyperlight builds a custom sysroot for x86_64-hyperlight-none target.
54-
# rust-cache cleans "anything not a dependency" from target dirs, removing the sysroot.
55-
# We cache sysroot separately to avoid rebuilding it (~10s) on every run.
56-
- name: Sysroot cache
57-
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
58-
with:
59-
path: |
60-
src/tests/rust_guests/target/sysroot
61-
src/tests/rust_guests/target-non-pie/sysroot
62-
key: sysroot-linux-${{ matrix.config }}-${{ hashFiles('rust-toolchain.toml') }}
63-
64-
- name: Rust cache
65-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
66-
with:
67-
shared-key: "nightly-${{ matrix.config }}"
68-
cache-on-failure: "true"
69-
workspaces: |
70-
. -> target
71-
src/tests/rust_guests -> target
72-
73-
- name: Set up sccache
74-
uses: ./.github/actions/setup-sccache
75-
7653
- name: Install cargo-hyperlight
7754
run: just ensure-cargo-hyperlight
7855

‎.github/workflows/copilot-setup-steps.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727
with:
2828
toolchain: nightly
2929
components: rustfmt
30+
# The agent runs on branches, where saved caches serve only that branch and evict those of main.
31+
cache: false
3032

3133

3234
- uses: hyperlight-dev/ci-setup-workflow@2f4142ba17cf573af44fc1e1f1ffc743daded5b3 # v1.10.0

‎.github/workflows/dep_benchmarks.yml‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,12 @@ jobs:
8282
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8383

8484
- name: Rust cache
85-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
85+
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
8686
with:
87+
prefix-key: v1-rust
8788
shared-key: "${{ inputs.arch }}-${{ runner.os }}-${{ inputs.hypervisor }}-release"
8889
save-if: "false"
8990

90-
- name: Set up sccache
91-
uses: ./.github/actions/setup-sccache
92-
9391
- name: Download Rust guests
9492
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
9593
with:
@@ -116,6 +114,13 @@ jobs:
116114
name: c-guests-${{ inputs.arch }}-release-baseline
117115
path: ${{ runner.temp }}/baseline-guests/c/
118116

117+
# The baseline builds in its own target directory. Cargo fingerprints
118+
# path dependencies by mtime and workspace path, so two checkouts cannot
119+
# share one. A copy of the restored cache gives it the dependencies.
120+
- name: Seed baseline target directory
121+
if: inputs.baseline_ref != ''
122+
run: if [ -d target ]; then cp -a target "$RUNNER_TEMP/baseline-target"; fi
123+
119124
# Both commits are measured on this machine, so the comparison reflects
120125
# them rather than the difference between two runners. The branch point
121126
# is read off the merge this run validates, so on anything else there is
@@ -130,7 +135,7 @@ jobs:
130135
echo "::error::HEAD is not a merge, so ${{ inputs.baseline_ref }} is not the branch point"
131136
exit 1
132137
}
133-
just bench-against ${{ inputs.baseline_ref }} "$RUNNER_TEMP/baseline-guests"
138+
just bench-against ${{ inputs.baseline_ref }} "$RUNNER_TEMP/baseline-guests" "" "$RUNNER_TEMP/baseline-target"
134139
else
135140
just bench-ci main
136141
fi

‎.github/workflows/dep_build_guests.yml‎

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ on:
3030
required: false
3131
type: string
3232
default: ""
33+
prime_cache:
34+
description: >-
35+
Build the Rust guests from a cold target and save the caches. Skips
36+
the build when they are up to date, and skips C guests and uploads.
37+
required: false
38+
type: boolean
39+
default: false
3340

3441
env:
3542
CARGO_TERM_COLOR: always
@@ -87,45 +94,51 @@ jobs:
8794
id: sysroot-cache
8895
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
8996
with:
90-
path: |
91-
src/tests/rust_guests/target/sysroot
92-
src/tests/rust_guests/target-non-pie/sysroot
97+
path: src/tests/rust_guests/target/sysroot
9398
key: sysroot-linux-${{ inputs.arch }}-${{ inputs.config }}-${{ hashFiles('rust-toolchain.toml') }}
9499

100+
# Priming builds cold, so the entry holds only what this commit needs.
95101
- name: Rust cache
96-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
102+
id: rust-cache
103+
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
97104
with:
105+
prefix-key: v1-rust
98106
shared-key: "guests-${{ inputs.arch }}-${{ inputs.config }}"
99-
cache-on-failure: "true"
100-
# Only save on main as caches are not shared across branches.
101-
# https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache
102-
save-if: ${{ github.ref == 'refs/heads/main' }}
107+
lookup-only: ${{ inputs.prime_cache }}
108+
save-if: ${{ inputs.prime_cache }}
103109
workspaces: |
104-
. -> target
105110
src/tests/rust_guests -> target
111+
src/tests/rust_guests -> target-non-pie/build
106112
107-
- name: Set up sccache
108-
uses: ./.github/actions/setup-sccache
113+
- name: Check whether the caches are up to date
114+
id: prime
115+
if: inputs.prime_cache
116+
run: echo "skip=${{ steps.rust-cache.outputs.cache-hit == 'true' && steps.sysroot-cache.outputs.cache-hit == 'true' }}" >> "$GITHUB_OUTPUT"
109117

110118
- name: Install cargo-hyperlight
119+
if: steps.prime.outputs.skip != 'true'
111120
run: just ensure-cargo-hyperlight
112121

113122
- name: Build Rust guests
123+
if: steps.prime.outputs.skip != 'true'
114124
run: |
115125
just build-rust-guests ${{ inputs.config }}
116126
just move-rust-guests ${{ inputs.config }}
117127
118128
- name: Build non-PIE Rust guests
129+
if: steps.prime.outputs.skip != 'true'
119130
run: |
120131
just build-rust-guests-non-pie ${{ inputs.config }}
121132
just move-rust-guests-non-pie ${{ inputs.config }}
122133
123134
- name: Build C guests
135+
if: ${{ !inputs.prime_cache }}
124136
run: |
125137
just build-c-guests ${{ inputs.config }}
126138
just move-c-guests ${{ inputs.config }}
127139
128140
- name: Upload Rust guests
141+
if: ${{ !inputs.prime_cache }}
129142
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
130143
with:
131144
name: rust-guests-${{ inputs.arch }}-${{ inputs.config }}${{ inputs.artifact_suffix }}
@@ -135,6 +148,7 @@ jobs:
135148
if-no-files-found: error
136149

137150
- name: Upload C guests
151+
if: ${{ !inputs.prime_cache }}
138152
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
139153
with:
140154
name: c-guests-${{ inputs.arch }}-${{ inputs.config }}${{ inputs.artifact_suffix }}
@@ -143,13 +157,10 @@ jobs:
143157
if-no-files-found: error
144158

145159
# A job step, not a post-job step, so the save runs before rust-cache's
146-
# post-job cleanup deletes the sysroot. Only main saves, as caches are not
147-
# shared across branches.
160+
# post-job cleanup deletes the sysroot.
148161
- name: Save sysroot cache
149-
if: ${{ github.ref == 'refs/heads/main' && steps.sysroot-cache.outputs.cache-hit != 'true' }}
162+
if: ${{ inputs.prime_cache && steps.sysroot-cache.outputs.cache-hit != 'true' }}
150163
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
151164
with:
152-
path: |
153-
src/tests/rust_guests/target/sysroot
154-
src/tests/rust_guests/target-non-pie/sysroot
165+
path: src/tests/rust_guests/target/sysroot
155166
key: ${{ steps.sysroot-cache.outputs.cache-primary-key }}

‎.github/workflows/dep_build_test.yml‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,15 @@ jobs:
106106
$llvmPath >> $env:GITHUB_PATH
107107
108108
- name: Rust cache
109-
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
109+
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
110110
with:
111+
prefix-key: v1-rust
111112
# Concurrent macOS runners share ~/.cargo/bin, so cleanup can remove Cargo from another job.
112113
cache-bin: ${{ runner.os != 'macOS' }}
113114
shared-key: "${{ inputs.arch }}-${{ runner.os }}-${{ inputs.hypervisor }}-${{ inputs.config }}"
114-
cache-on-failure: "true"
115-
# Only save on main as caches are not shared across branches.
116-
# https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache
117-
save-if: ${{ github.ref == 'refs/heads/main' }}
118-
119-
- name: Set up sccache
120-
uses: ./.github/actions/setup-sccache
115+
# PrimeCaches writes this entry. Keep the steps before this one in
116+
# sync with its host job.
117+
save-if: "false"
121118

122119
- name: Download Rust guests
123120
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2

0 commit comments

Comments
 (0)