Skip to content

ci: restore-keys for the LLBC caches, and two jobs' worth of duplicated work removed - #1347

Merged
youknowone merged 3 commits into
mainfrom
str
Aug 19, 2026
Merged

ci: restore-keys for the LLBC caches, and two jobs' worth of duplicated work removed#1347
youknowone merged 3 commits into
mainfrom
str

Conversation

@youknowone

@youknowone youknowone commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Three CI changes, measured rather than guessed. Baseline is run 32172685070
(all jobs green): 373 min of wall across 13 jobs, or 1363 min once the
macOS ×10 and Windows ×2 multipliers are applied
, with the critical path at
78 min (prepare Charon/LLBC (ubuntu) 11.6 → pyre/check.py (ubuntu) 66.7).

1. The per-crate LLBC caches get a restore-keys fallback

The four entries carried an exact key and nothing else, so a miss restored
nothing. The key is the wide digest — Compute LLBC fingerprints runs
before any .readfiles exists, so source= falls back to the whole cargo
closure there, and one edit anywhere misses all four crates. Every run
re-extracted the whole set: 10.6 min ubuntu, 19.5 windows, 22.3 macOS.

This is safe because the key is only a hint. extract-llbc.py recomputes each
crate's stamp against the current tree — narrowing source= through the
restored .readfiles — and compares it to the restored stamp as exact text
over source=/closure=/external=/charon=/layout_flags=. A restored
artefact that does not match is re-extracted, so a stale restore costs a
download and cannot reach the artefact.

Verified locally:

  • nothing changed → all four print skipping … (fingerprint unchanged) in 2s
  • a comment appended to pyre/pyre-jit/src/call_jit.rs, which is in pyre-jit's
    readfiles and no other crate's → pyre-jit alone re-extracts, the other
    three skip

Expected saving, from measured per-crate extraction times against the share of
the last 60 commits on main that touch no file in each crate's readfiles:

crate seconds share commits touching nothing of its
pyre-interpreter 376 66% 48%
pyre-jit 106 18% 33%
pyre-object 53 9% 73%
majit-rlib 40 7% 92%

All four must re-extract on 8% of commits; weighting share by hit rate puts the
expected saving near half of each Extract step.

2. The pyre-wasm web-binding build moves off the check.py leg

It sat ahead of Run pyre/check.py on the premise that building
--features web first would leave check.py's later --features wasm-host
build sharing compiled dependencies. Measured on a cold target dir:

arm crates wall
build --features web cold 328 6m00
build --features wasm-host after it 166 1m42
build --features wasm-host cold, alone 323 2m32

The sharing is real and worth 50 seconds for 6 minutes spent — half the
graph still recompiles because check.py sets
RUSTFLAGS='-C link-arg=--export-table -C link-arg=--growable-table --cfg getrandom_backend="custom"'
and the web step sets none. On the ubuntu runner the step measures 11.7 min.

The build itself is unchanged — this keeps the full cargo build compile
signal, it just runs somewhere cheaper. sandbox-build already carries the
checkout, toolchain, Cargo cache and prepared Charon/LLBC set it needs, runs on
the same image, and at 15.4 min sits far off the critical path. It goes first in
that job so the signal still arrives early. Nothing executes the artefact either
way; check.py writes its own pyre_wasm.wasm. The job is renamed
sandbox e2e + wasm web build (ubuntu-24.04).

3. The CPython suite becomes trailing steps of cargo test (ubuntu-24.04)

cpython-tests repeated the checkout, toolchain install, Cargo cache restore
and Charon/LLBC download that cargo-test-linux already does on the same runner
image, and needed the same prepared artefacts. Its two steps move into that
job's shared step anchor under runner.os == 'Linux', and the job is deleted.

Both carry !cancelled(), so a failing cargo pass above them cannot suppress
the suite the way plain step ordering would — as separate jobs neither could
hide the other. cargo-test-linux takes the deleted job's timeout-minutes,
raised to 90 to cover the work now in it.

This one is the smallest of the three: it recovers about 1.4 min of duplicated
setup and one runner slot. It does not remove the release pyre-dynasm
build, which check.py still does separately.

Expected effect

before after
critical path 78 min (ubuntu) ~68 min (moves to windows)
multiplier-weighted total 1363 min ~1215 min

What to watch on the first run

sandbox-build has no Free up runner disk space step and now links a wasm32
release target on top of a native release pyre and a release e2e test binary.
If disk runs out there, that step can be copied across from cargo-test-linux.

Checked and deliberately not changed

  • Extracting LLBC once and fanning it out to the other hosts is not possible.
    Diffing llbc-Linux-X64 against llbc-macOS-ARM64 from one run,
    pyre-interpreter.ullbc.readfiles differs: macOS lists interp_kevent.rs,
    interp_kqueue.rs and select/mod.rs, which Linux never compiles. The
    artefacts describe different sets of functions, so the per-OS artefact naming
    is load-bearing. Only the *.wasm32-unknown-unknown.layouts.ullbc sidecars
    are byte-identical across hosts.
  • rust-cache is healthy. cargo test (ubuntu-24.04) on main reports
    Restored from cache key "v0-rust-X64-Linux-x64-…" full match: true,
    Cache Size: ~2628 MB. The 0.00m Post Run steps are an exact hit correctly
    skipping the save, not a broken cache.
  • Cutting benchmark subprocess spawns buys nothing. From the per-line
    timestamps in the check.py job logs, spawn overhead outside the measured
    seconds is 1.9 min on ubuntu (0.05s across 2149 spawns), 2.6 on windows, 1.6
    on macOS.
  • Skipping cargo test when no Rust changed would never fire — 0 of the
    last 40 commits on main leave *.rs/Cargo.toml/Cargo.lock untouched.

Summary by CodeRabbit

  • Bug Fixes

    • Improved build-cache recovery so stale artifacts can be revalidated and selectively restored.
    • Added extended Linux test timeouts and conditional support for CPython 3.14.
  • Tests

    • Consolidated CPython testing with Linux cargo tests while preserving independent execution.
    • Included the WebAssembly web build in sandbox validation.
  • Documentation

    • Updated testing documentation to reflect the current CI workflow and job locations.

The `cpython-tests` job repeated the checkout, toolchain install, Cargo
cache restore and Charon/LLBC download that `cargo-test-linux` already
does on the same runner image, and needs the same prepared artifacts.
Its two steps move into that job's shared step anchor, guarded on
`runner.os == 'Linux'` so the macOS and Windows copies skip them, and the
job is deleted.

Both steps also carry `!cancelled()`, so a failing cargo pass above them
no longer suppresses the suite the way plain step ordering would; as
separate jobs neither could hide the other.

`cargo-test-linux` takes the deleted job's `timeout-minutes`, raised to
90 to cover the work now in it. `pyre/cpython_tests/README.md` and the
`--cpython-suite` docstring in `pyre/check.py` are repointed.

Assisted-by: Claude
The step sat ahead of `Run pyre/check.py` on the premise that building
`--features web` first would leave check.py's later `--features wasm-host`
build sharing its compiled dependencies. Measured on a cold target dir:
the web build compiles 328 crates in 6m00 and leaves the wasm-host build
compiling 166 instead of 323 — 1m42 against a 2m32 cold control. Half the
graph still recompiles because check.py sets
`RUSTFLAGS='-C link-arg=--export-table -C link-arg=--growable-table --cfg
getrandom_backend="custom"'` and the web step sets none. On the ubuntu
runner the step measures 11.7 min and the saving it buys is worth about
1.7.

It moves to `sandbox-build`, which already has the checkout, toolchain,
Cargo cache and prepared Charon/LLBC set it needs, is on the same runner
image, and at 15.4 min sits far off the run's critical path. It goes
first in that job so the compile signal still arrives early. Nothing
executes the artefact either way; check.py writes its own pyre_wasm.wasm.

That job is renamed to `sandbox e2e + wasm web build (ubuntu-24.04)`.

Assisted-by: Claude
The four entries carried an exact key and nothing else, so a miss
restored nothing. The key is the wide digest — `Compute LLBC
fingerprints` runs before any `.readfiles` exists, so `source=` is the
whole cargo closure there and one edit anywhere misses all four. Every
run therefore re-extracted the whole set: 10.6 min on ubuntu, 19.5 on
windows, 22.3 on macOS.

With a `restore-keys` prefix a miss falls back to the crate's most
recent entry, and `extract-llbc.py` adjudicates: it recomputes each
crate's stamp against the current tree, narrowing `source=` through the
restored `.readfiles`, and compares it to the restored stamp as exact
text. Verified locally — a comment appended to
`pyre/pyre-jit/src/call_jit.rs`, which is in pyre-jit's readfiles and no
other crate's, re-extracts pyre-jit alone and skips the other three; with
nothing changed all four skip in 2s.

The key therefore only chooses what is offered. A stale restore costs a
download and is re-extracted, and cannot reach the artefact.

Measured shares of one extraction: pyre-interpreter 376s, pyre-jit 106s,
pyre-object 53s, majit-rlib 40s. Over the last 60 commits on main the
share of commits touching no file in a crate's readfiles is 48%, 33%,
73% and 92% respectively, and 8% of commits touch all four. Weighting
the first by the second puts the expected saving near half of each
Extract step.

Assisted-by: Claude
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d2dbf2d6-e04d-4e96-9a3c-fe377c07e728

📥 Commits

Reviewing files that changed from the base of the PR and between 61bbc11 and 5ee4f56.

📒 Files selected for processing (3)
  • .github/workflows/pyre-ci.yml
  • pyre/check.py
  • pyre/cpython_tests/README.md

Included review availability: Your plan provides up to 2 included reviews per hour; 0 remain after this review.


Walkthrough

The CI workflow adds per-crate LLBC cache fallbacks, integrates CPython tests into Linux cargo testing, removes the standalone CPython job, and moves the wasm web build into the sandbox job. Related documentation names the new CPython job.

Changes

CI workflow updates

Layer / File(s) Summary
LLBC cache fallback configuration
.github/workflows/pyre-ci.yml
LLBC caches now use crate-specific restore-key prefixes. Documentation describes fingerprint validation and selective re-extraction of stale artifacts.
CPython suite integration
.github/workflows/pyre-ci.yml, pyre/check.py, pyre/cpython_tests/README.md
The Linux cargo-test job installs CPython 3.14 conditionally and runs the release CPython suite with parallel jobs, cancellation-aware conditions, and per-module timeouts. Documentation references cargo-test-linux.
Sandbox wasm web build
.github/workflows/pyre-ci.yml
The standalone CPython job is removed. The sandbox job installs the wasm32 target and builds the release pyre-wasm web feature.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 5ee4f

The PR improves CI cache reuse and removes duplicated build and test setup without introducing an actionable merge-blocking risk; it is merge-ready after normal checks.

Sequence Diagram(s)

sequenceDiagram
  participant cargo-test-linux
  participant CPython-3.14
  participant CPython-suite
  participant sandbox-e2e
  cargo-test-linux->>CPython-3.14: conditional setup on Linux
  cargo-test-linux->>CPython-suite: build and run release regression suite
  CPython-suite-->>cargo-test-linux: return parallel test results
  sandbox-e2e->>sandbox-e2e: install wasm32 target
  sandbox-e2e->>sandbox-e2e: build pyre-wasm web feature
Loading

Possibly related PRs

Poem

A rabbit watched the caches grow wise,
With fresher crates beneath the skies.
CPython hops where cargo runs,
While wasm builds beneath the sun.
“One green workflow!” the rabbit sings.

🚥 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 clearly identifies the LLBC cache restore-key changes and the removal of duplicated CI work, which are central objectives of the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch str

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 5ee4f5643d

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +204 to +205
restore-keys: |
llbc2-majit-rlib-${{ runner.os }}-${{ runner.arch }}-${{ env.CHARON_VERSION }}-

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 Avoid restoring LLBC entries that the stamp must reject

On every primary-key miss caused by a closure edit, this fallback cannot produce the advertised per-crate skip: Compute LLBC fingerprints calculates source= without a .readfiles sidecar, so it falls back to the same conservative input set hashed into the cached stamp's closure= field. Therefore a changed primary digest also means the restored entry's closure= differs from the current stamp, and extract()'s byte-for-byte stamp comparison rejects it and re-extracts the crate. The new fallback consequently downloads a stale LLBC on each miss without avoiding extraction; the key or freshness gate needs to be aligned so a fallback can actually pass.

AGENTS.md reference: AGENTS.md:L67-L72

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 5ee4f56).
Updated: 2026-08-19T06:28:34.009Z

Files in the reviewed diff
.github/workflows/pyre-ci.yml
pyre/check.py
pyre/cpython_tests/README.md

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

None.

4. Structural adaptations

None.

@youknowone
youknowone merged commit e0e3ddf into main Aug 19, 2026
21 of 22 checks passed
@youknowone
youknowone deleted the str branch August 19, 2026 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant