--- # Throwaway diagnostic: why does master's ccache serve only ~14% of calls when a # whole pull-request cache is restored? # # It builds the Arch leg's real command (`--server --debug --test`, the same as # .github/workflows/desktop-build.yml) three times, with no Actions cache at all, # so the repository's 10 GB quota is untouched: # # 1. cold, with a 6G bound that cannot be the limit: `du` and the ccache stats # give the true working set of one configuration. # 2. again from a deleted build directory with the same image, sources and # flags: anything below ~95% hits means the hash inputs differ, not the size. # 3. again after `ccache --recompress 1`, which is the candidate fix if one # configuration turns out to be larger than a per-leg bound: it measures what # the same configuration costs when the objects are compressed. # # Two runs of this workflow also compare the image id and the compiler's mtime, # which is what ccache hashes by default (compiler_check = mtime). name: ccache probe on: push: branches: - ci/ccache-probe pull_request: branches: - master concurrency: group: ${{ github.workflow }} @ ${{ github.ref_name }} cancel-in-progress: true jobs: probe: name: Arch probe runs-on: ubuntu-latest timeout-minutes: 150 env: NAME: Arch CACHE: ${{ github.workspace }}/.cache/Arch # Far above any candidate working set: a cache that evicts cannot be measured. CCACHE_BOUND: 6G # The leg's own invocation, so the probe cannot measure a configuration the # workflow does not build. LEG_ARGS: --server --debug --test --cmake-generator Ninja steps: - name: "Checkout" uses: actions/checkout@v7 - name: "Build image and record the compiler's identity" shell: bash run: | source .ci/docker.sh --build echo "=== disk available to the build" df -h / | sed 's/^/ /' echo "=== image" docker image inspect --format 'image id: {{.Id}}' "$IMAGE_NAME" docker image inspect --format 'created: {{.Created}}' "$IMAGE_NAME" echo "=== compiler as ccache sees it (compiler_check = mtime hashes mtime and size)" docker run --rm "$IMAGE_NAME" bash -c 'for c in c++ cc gcc g++; do p="$(command -v $c)"; [ -n "$p" ] && stat -c "%n size=%s mtime=%Y" "$p"; done; c++ --version | head -1' - name: "Build 1 cold, 6G bound" shell: bash run: | source .ci/docker.sh RUN $LEG_ARGS --ccache "$CCACHE_BOUND" # du cannot see a size the cache was not allowed to keep, which is why the # bound is 6G here. The stats travel inside the cache directory, so the # numbers below are this run's, not a restored history. - name: "Working set of one configuration, uncompressed" shell: bash run: | source .ci/docker.sh echo "=== ccache dir on the host" du -sh "$CCACHE_DIR" find "$CCACHE_DIR" -type f -name '*.result' | wc -l | sed 's/^/result files: /' find "$CCACHE_DIR" -type f -name '*.manifest' | wc -l | sed 's/^/manifest files: /' echo "=== config in effect" docker run --rm --mount "type=bind,source=$CCACHE_DIR,target=/.ccache" \ --env CCACHE_DIR=/.ccache "$IMAGE_NAME" ccache --show-config | grep -E 'compiler_check|hash_dir|compression|direct_mode|depend_mode' - name: "Build 2, same image, same sources, deleted build directory" shell: bash run: | rm -rf build source .ci/docker.sh RUN $LEG_ARGS --ccache "$CCACHE_BOUND" # A compressed cache is the only way one configuration can fit a per-leg # bound, so measure it on the cache build 2 just used. - name: "Working set after recompressing to level 1" shell: bash run: | source .ci/docker.sh docker run --rm --mount "type=bind,source=$CCACHE_DIR,target=/.ccache" \ --env CCACHE_DIR=/.ccache "$IMAGE_NAME" ccache --recompress 1 du -sh "$CCACHE_DIR" - name: "Build 3, compressed cache, deleted build directory" shell: bash run: | rm -rf build source .ci/docker.sh # Writes stay compressed, so this is the configuration a fix would ship. export RUN_ARGS="$RUN_ARGS -e CCACHE_COMPRESS=1" RUN $LEG_ARGS --ccache "$CCACHE_BOUND" echo "=== cache after build 3" du -sh "$CCACHE_DIR"