Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/actions/deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ runs:
shell: bash
working-directory: ${{ fromJSON(inputs.job).dir }}/upstream
env:
INSTALL: ${{ fromJSON(inputs.job).install }}
run: eval "$INSTALL"
DEPS_INSTALL_COMMAND: ${{ fromJSON(inputs.job).install }}
run: eval "$DEPS_INSTALL_COMMAND"
- if: steps.install.outcome == 'failure'
shell: bash
working-directory: ${{ fromJSON(inputs.job).dir }}
Expand Down Expand Up @@ -168,6 +168,7 @@ runs:
- if: always() && steps.ready.outcome == 'success'
shell: bash
env:
DEPS_RESTORED_KEY: ${{ steps.restore-actions-cache.outputs.cache-matched-key }}
THROUGHPUT_OUTCOME_RESTORE: ${{ fromJSON(inputs.job).lane == 'boringcache' && steps.restore-boringcache.outcome || steps.restore-actions-cache.outcome }}
THROUGHPUT_OUTCOME_RESTORE_CHECK: ${{ fromJSON(inputs.job).kind == 'verify' && steps.restore-check.outcome || '' }}
THROUGHPUT_OUTCOME_INSTALL: ${{ steps.install.outcome }}
Expand Down
17 changes: 14 additions & 3 deletions .github/actions/phase/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ inputs:
cadence:
required: false
default: ""
cache-source:
required: false
default: ""

runs:
using: composite
Expand All @@ -54,10 +57,12 @@ runs:
PHASE: ${{ inputs.phase }}
RUN_ID: ${{ inputs.run-id }}
CADENCE: ${{ inputs.cadence }}
CACHE_SOURCE: ${{ inputs.cache-source }}
run: |
echo "$HOME/.local/share/mise/shims" >> "$GITHUB_PATH"
{
echo "BENCH_CADENCE=$CADENCE"
echo "BENCH_CACHE_SOURCE=$CACHE_SOURCE"
echo "BENCH_CASE=$CASE"
echo "BENCH_LANE=$LANE"
echo "BENCH_RUNNER=$RUNNER"
Expand Down Expand Up @@ -87,10 +92,10 @@ runs:
with:
team: ${{ env.TURBO_TEAM_ID }}

- if: contains(inputs.setup, 'namespace')
- if: contains(format(' {0} ', inputs.setup), ' namespace ')
uses: namespacelabs/nscloud-setup@df198f982fcecfb8264bea3f1274b56a61b6dfdc # v0

- if: contains(inputs.setup, 'namespace')
- if: contains(format(' {0} ', inputs.setup), ' namespace ')
uses: namespacelabs/nscloud-setup-buildx-action@d059ed7184f0bc7c8b27e8810cea153d02bcc6dd # v0

- if: contains(inputs.setup, 'nix')
Expand Down Expand Up @@ -126,7 +131,7 @@ runs:
username: ${{ github.actor }}
password: ${{ github.token }}

- if: contains(inputs.setup, 'buildx') || contains(inputs.setup, 'namespace')
- if: contains(inputs.setup, 'buildx') || contains(format(' {0} ', inputs.setup), ' namespace ')
shell: bash
run: docker buildx ls

Expand Down Expand Up @@ -192,6 +197,12 @@ runs:
shell: bash
run: bundle exec bin/bench start "$BENCH_CASE" --lane "$BENCH_LANE"

- if: steps.prepare.outputs.ready == 'true' && contains(inputs.setup, 'blacksmith-builder')
uses: useblacksmith/setup-docker-builder@19215110ab936351210feebdfa5b440b4493e184
with:
cache-key: ${{ env.BENCH_SCOPE }}
nofallback: true

- if: steps.prepare.outputs.ready == 'true' && contains(inputs.setup, 'kache')
shell: bash
env:
Expand Down
16 changes: 12 additions & 4 deletions .github/workflows/deps.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: Dependency cache update

on:
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
inputs:
mode:
Expand All @@ -16,6 +18,10 @@ on:
description: only this case, for example discourse-bundler (optional)
type: string
default: ""
runner:
description: runner keys, space separated; empty uses all four providers
type: string
default: ""
cli_artifact:
description: BoringCache artifact id of a candidate CLI to run instead of the pinned release; never recorded (optional)
type: string
Expand Down Expand Up @@ -65,10 +71,12 @@ jobs:
- id: matrix
env:
RUN_ID: ${{ github.run_id }}
STEP: ${{ inputs.step }}
STEP: ${{ inputs.step || '0' }}
PREFLIGHT: ${{ inputs.mode == 'preflight' && 'true' || '' }}
CASE: ${{ inputs.case }}
run: bundle exec ruby scripts/deps.rb matrix --run-id "$RUN_ID" --step "$STEP" ${PREFLIGHT:+--preflight} ${CASE:+--case "$CASE"} >> "$GITHUB_OUTPUT"
DAILY: ${{ github.event_name == 'schedule' && 'true' || '' }}
RUNNERS: ${{ inputs.runner }}
run: bundle exec ruby scripts/deps.rb matrix --run-id "$RUN_ID" --step "$STEP" ${PREFLIGHT:+--preflight} ${CASE:+--case "$CASE"} ${RUNNERS:+--runner "$RUNNERS"} ${DAILY:+--daily} >> "$GITHUB_OUTPUT"
- uses: ./.github/actions/throughput-cleanup
with:
prefix: deps-
Expand Down Expand Up @@ -112,7 +120,7 @@ jobs:
verify:
needs: [plan, update]
if: ${{ !cancelled() && needs.plan.result == 'success' }}
name: "verify: ${{ matrix.case }} · ${{ matrix.machine }} · ${{ matrix.lane }}"
name: "verify: ${{ matrix.case }} · ${{ matrix.machine }} · ${{ matrix.lane }} · cache from ${{ matrix.producer }}"
runs-on: ${{ matrix.runs_on }}
timeout-minutes: 60
permissions: *lane_permissions
Expand Down Expand Up @@ -145,7 +153,7 @@ jobs:

publish:
needs: [plan, seed, update, verify]
if: ${{ !cancelled() && needs.plan.result == 'success' && github.ref == 'refs/heads/main' && inputs.mode == 'run' && inputs.cli_artifact == '' && !inputs.cli_jsonl }}
if: ${{ !cancelled() && needs.plan.result == 'success' && github.ref == 'refs/heads/main' && inputs.mode != 'preflight' && inputs.cli_artifact == '' && !inputs.cli_jsonl }}
runs-on: ubuntu-24.04
permissions:
contents: write
Expand Down
24 changes: 16 additions & 8 deletions .github/workflows/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ on:
type: string
required: true
mode:
description: fresh (cold then warm), rolling (the next upstream commit), or preflight (setup and credential probes only)
description: fresh (cold then warm), rolling (next commit), sample (completed GitHub commit), or preflight (setup probes)
type: choice
options: [fresh, rolling, preflight]
options: [fresh, rolling, sample, preflight]
default: fresh
lane:
description: only these lanes, space separated (optional, for debugging one lane)
type: string
required: false
default: ""
runner:
description: sample only, runner keys such as github depot-8 (optional)
type: string
default: ""
cli:
description: CLI release tag instead of the pinned version, for example vcli-canary-<sha> (optional, fresh and preflight only)
type: string
Expand All @@ -35,7 +39,7 @@ on:
run-name: ${{ inputs.tool }} - ${{ inputs.project }}${{ inputs.mode != 'fresh' && format(' ({0})', inputs.mode) || '' }}${{ inputs.step && format(' step {0}', inputs.step) || '' }}${{ inputs.cli && format(' [{0}]', inputs.cli) || '' }}

concurrency:
group: ${{ inputs.mode == 'rolling' && format('rolling-{0}-{1}', inputs.tool, inputs.project) || format('run-{0}', github.run_id) }}
group: ${{ (inputs.mode == 'rolling' || inputs.mode == 'sample') && format('rolling-{0}-{1}', inputs.tool, inputs.project) || format('run-{0}', github.run_id) }}
cancel-in-progress: false

permissions:
Expand Down Expand Up @@ -65,17 +69,20 @@ jobs:
LANE: ${{ inputs.lane }}
CLI: ${{ inputs.cli }}
STEP: ${{ inputs.step }}
SAMPLE: ${{ inputs.mode == 'sample' && 'true' || '' }}
RUNNER: ${{ inputs.runner }}
run: |
bash scripts/checkout-records.sh
matrix=$(bundle exec bin/bench matrix "$PROJECT" --tool "$TOOL" ${ROLLING:+--rolling} ${LANE:+--lane "$LANE"} ${CLI:+--cli "$CLI"} ${STEP:+--step "$STEP"} --results results)
if [ -n "$RUNNER" ] && [ -z "$SAMPLE" ]; then echo 'runner selection requires sample mode' >&2; exit 1; fi
matrix=$(bundle exec bin/bench matrix "$PROJECT" --tool "$TOOL" ${ROLLING:+--rolling} ${SAMPLE:+--sample} ${RUNNER:+--runner "$RUNNER"} ${LANE:+--lane "$LANE"} ${CLI:+--cli "$CLI"} ${STEP:+--step "$STEP"} --results results)
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
if [ "$matrix" = '[]' ]; then
echo 'No benchmark jobs are due for this selection.' >> "$GITHUB_STEP_SUMMARY"
fi

cold:
needs: plan
if: ${{ inputs.mode != 'rolling' && needs.plan.outputs.matrix != '[]' }}
if: ${{ (inputs.mode == 'fresh' || inputs.mode == 'preflight') && needs.plan.outputs.matrix != '[]' }}
name: "${{ inputs.mode == 'preflight' && 'preflight' || 'cold' }}: ${{ matrix.label }}"
runs-on: ${{ matrix.runs_on }}
timeout-minutes: 180
Expand Down Expand Up @@ -119,14 +126,15 @@ jobs:
lane: ${{ matrix.lane }}
runner: ${{ matrix.runner }}
setup: ${{ matrix.setup }}
phase: ${{ inputs.mode == 'preflight' && 'preflight' || github.job }}
phase: ${{ (inputs.mode == 'preflight' || inputs.mode == 'sample') && inputs.mode || github.job }}
run-id: ${{ github.run_id }}
sha: ${{ matrix.sha }}
step: ${{ matrix.step }}
cache-scope: ${{ matrix.cache_scope }}
cli-release: ${{ matrix.cli }}
continues: ${{ matrix.continues }}
cadence: ${{ matrix.cadence }}
cache-source: ${{ matrix.source }}

warm:
needs: [plan, cold]
Expand All @@ -141,8 +149,8 @@ jobs:

rolling:
needs: plan
if: ${{ inputs.mode == 'rolling' && needs.plan.outputs.matrix != '[]' }}
name: "rolling: ${{ matrix.label }}"
if: ${{ (inputs.mode == 'rolling' || inputs.mode == 'sample') && needs.plan.outputs.matrix != '[]' }}
name: "${{ inputs.mode }}: ${{ matrix.label }}"
runs-on: ${{ matrix.runs_on }}
timeout-minutes: 180
permissions: *lane_permissions
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/samples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Weekly runner samples

on:
schedule:
- cron: "31 2 * * 1"
workflow_dispatch:

permissions:
contents: read
actions: write

jobs:
dispatch:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- tool: Docker
project: posthog
- tool: Rust/Cargo
project: zed
- tool: Docker
project: chroma
env:
GH_TOKEN: ${{ github.token }}
TOOL: ${{ matrix.tool }}
PROJECT: ${{ matrix.project }}
steps:
- run: gh workflow run project.yml --repo "$GITHUB_REPOSITORY" --ref main -f tool="$TOOL" -f project="$PROJECT" -f mode=sample
17 changes: 15 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This repository benchmarks BoringCache against other cache providers on real pro

## Rules every change keeps

- Keep benchmark measurements, outcomes, reproducible configuration and customer-accessible CLI/action logs here. Do not commit internal investigation notes, private operations details or server-side MCP snapshots.

- Every lane of a case runs the same build command on the same source commit. Lanes differ only in their documented cache setup.
- Every lane caches the same content: dependencies and build outputs. If one lane restores a dependency store, all do.
- Use each provider's official, documented setup. Cite the doc in the commit when adding or changing a lane. Never spoof events or patch around a provider bug; record the failure instead.
Expand All @@ -30,9 +32,9 @@ This repository benchmarks BoringCache against other cache providers on real pro

- Fresh runs build `start_sha` cold then warm. A cold cannot be retried inside a run; dispatch a new fresh run.
- Rolling keeps one position per tool and project. Every lane builds the same next first-parent commit, and the next run moves on whether or not that commit failed. Projects without new upstream commits plan nothing.
- Each lane rolls on one fixed cache scope, `<lane>-<runner>-rolling`, which every step restores and saves. Lanes a case lists under `[nightly]` build only the first rolling step of each UTC day, on the same scope; the report compares them with each other. Fresh runs use their own run-scoped caches and never touch it, so a lane's first rolling step starts empty.
- Each regular lane rolls on one fixed cache scope, `<lane>-<runner>-rolling`. `[samples]` reserves selected lanes for weekly `mode=sample` builds of the latest completed GitHub source commit; samples also run when upstream has no new commit and do not advance rolling. They share the project's rolling concurrency group. BoringCache samples restore the regular GitHub cache without publishing; native caches persist between samples. Fresh runs use their own scopes and exclude sample lanes. Legacy `[nightly]` behavior remains supported for historical configurations.
- When a lane, runner or rolling series leaves `[runs]`, delete its BoringCache tags with `boringcache rm --no-platform --no-git boringcache/benchmarks <tags>`, listing them by exact name. Its records stay in `results/`.
- `schedule.yml` runs `bin/bench tick` every 15 minutes. It checks each idle project in `rolling.toml` against its upstream branch and dispatches only when a commit is due at its configured stride. Active or queued projects wait for a later tick. An upstream check failure is reported and fails the tick without dispatching that project. The workflow's concurrency group runs one rolling run per project at a time.
- `schedule.yml` runs `bin/bench tick` every 15 minutes. It checks each idle project in `rolling.toml` against its upstream branch and dispatches only when a commit is due at its configured stride. Active or queued rolling and sample projects wait for a later tick. An upstream check failure is reported and fails the tick without dispatching that project. The workflow's concurrency group runs one rolling run per project at a time.
- `prune-buildkit.yml` deletes stale BuildKit `type=gha` blobs every 2 hours.
- `report.yml` regenerates `data/results.json` and `data/report.md` hourly from recorded results. Experimental lanes are excluded.
- A failed build or output check is recorded first, then fails its job. A failure in `prepare` leaves no record; that lane continues at the next step.
Expand All @@ -57,10 +59,21 @@ To check a fix once, run a fresh run of the affected lanes with a published cana
gh workflow run project.yml --ref main -f tool=<Tool> -f project=<project> -f mode=fresh -f lane="<lanes>" -f cli=vcli-canary-<sha>
```

- Confirm the canary contains the intended change before benchmarking it.
- Canary records carry `versions.boringcache_release`, and the report shows that tag in the CLI column, so they never merge with release rows. Compare them with the release fresh rows at the same commit.
- Pin a case in `[cases]` only when it needs an unreleased fix to roll, and remove the entry once a release with the fix is pinned. Bump `boringcache` only after the release is published.

## Investigate a failure

Classify it before changing anything:

- **Harness** (prepare, wiring, workflow): fix it here with a test.
- **BoringCache product**: retain the failed benchmark record. Investigate and fix the product outside this repository. Leave the lane failing until a released CLI carries the fix.
- **Other provider**: keep the lane failing and note it. If the provider cannot run the case, remove the lane and log the outcome under "Removed lanes" in `PLAN.md` with run links.
- **Upstream** (their build or a transient download): record it and keep rolling.
- **Not a measurement** (a build that passed while its provider served no cache, such as a lapsed plan): add `"excluded": "<reason and evidence>"` to those records, and to the next step if it restored a cache the outage never saved. The report leaves them out; the records stay.
- **Unrecorded restore** (a rolling record with `cache_restore_tracked` but no `cache_restored_key`, as `cache-dance` lanes wrote before their restore moved to `actions/cache/restore`): with `gh` signed in, run `GITHUB_REPOSITORY=boringcache/benchmarks bundle exec bin/bench restored-keys --results results`. It fills the key only when the original job log shows that lane's restore before post-job cleanup.

## Checks

Run tests the way CI does, so ambient GitHub variables cannot change results:
Expand Down
Loading
Loading