Cache the cvc5 artifacts required to test the Pythonic API - #119
Merged
Conversation
Building cvc5 from scratch on every CI run is wasteful when its code has not changed. Cache the artifacts the tests actually need, keyed on the cvc5 commit, and skip the build when they can be restored. The cached artifacts are the Python bindings package and the cvc5 shared libraries it links against. The bindings embed an absolute rpath into the build tree, which is stable across runs, so they can be restored and used in place. Skipping the build additionally requires a hit on the dependencies cache: in a shared build, which --python-bindings requires, some dependencies, libpoly among them, are built as shared libraries under deps/install/lib and are loaded at run time. Installing the build dependencies is skipped along with the build. All that action provides is needed to build cvc5: the compilers and headers, ccache, and the num_proc variable. The libraries the cached artifacts load at run time are either part of the runner image, libgmp10 and libstdc++, or come from the cached build/deps. Note that this relies on the bindings not being linked against CLN, whose runtime package is not part of the runner image: --gpl only permits GPL dependencies, it does not select the CLN implementation, which is what --cln does. The cache keys track the configuration cvc5 is built with, now defined once in the CVC5_CONFIG variable, rather than the workflow file, so that unrelated changes to the workflow do not discard the cached artifacts. Finally, actually use ccache. The workflow set up a ccache cache and configured it, but cvc5 only uses ccache if the compiler launchers are passed to CMake, which its own CI does but this workflow did not, so nothing was ever cached. This matters because the artifacts cache turns over whenever the cvc5 default branch advances; a working ccache makes those rebuilds incremental. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Building cvc5 from scratch on every CI run is wasteful when its code has not
changed. This caches the artifacts the tests actually need, keyed on the cvc5
commit, and skips the build when they can be restored.
On a cache hit the job goes from around 14 minutes to under half a minute.
What is cached
The Python bindings package and the cvc5 shared libraries it links against.
The bindings embed an absolute rpath into the build tree, and the workspace
path is stable across runs, so they can be restored and used in place without
relinking.
Skipping the build additionally requires a hit on the dependencies cache: in a
shared build, which
--python-bindingsrequires, some dependencies, libpolyamong them, are built as shared libraries under
deps/install/liband areloaded at run time.
The cache is keyed on the cvc5 commit, so it can never serve bindings that do
not match the cvc5 revision that was just checked out. A pythonic API change
alone always hits; an upstream cvc5 commit always rebuilds.
Skipping the dependency installation
Everything the
install-dependenciesaction provides is needed to build cvc5:the compilers and headers, ccache, and the
num_procvariable. The librariesthe cached artifacts load at run time are either part of the runner image,
libgmp10 and libstdc++, or come from the cached
build/deps, so the action isskipped along with the build.
Note that this relies on the bindings not being linked against CLN, whose
runtime package is not part of the runner image. The production build does not
use CLN:
--gplonly permits GPL dependencies, it does not select the CLNimplementation, which is what
--clndoes. TheCheck the cached cvc5 artifactsstep guards this: if cvc5 ever links a new system library, it failson cache-hit runs with a clear message instead of failing inside the tests.
Two related fixes
The cache keys track the configuration cvc5 is built with, now defined once in
the
CVC5_CONFIGvariable, rather than the workflow file, so that unrelatedchanges to the workflow do not discard the cached artifacts.
The workflow also set up a ccache cache and configured it, but cvc5 only uses
ccache if the compiler launchers are passed to CMake, which its own CI does but
this workflow did not, so nothing was ever cached: every stored entry was
around 13 KiB, holding just the configuration and the statistics. Passing the
launchers takes the stored cache to around 24 MiB. This matters because the
artifacts cache turns over whenever the cvc5 default branch advances, and a
working ccache makes those rebuilds incremental.
Testing
Verified on the fork. The run against the final tree restored both caches,
skipped the dependency installation and the build, and passed the test suite
against the restored bindings in 24 seconds, compared to around 14 minutes for
the cold builds that preceded it.
🤖 Generated with Claude Code