Skip to content

Commit 07e9e26

Browse files
committed
docs: add CI cache strategy guide
1 parent b282400 commit 07e9e26

4 files changed

Lines changed: 143 additions & 0 deletions

File tree

docs/CI_CACHE.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Cross-run CI cache strategy
2+
3+
This is the consumer-facing checklist for carrying fbuild state across GitHub
4+
Actions runs. For the deeper design notes and matrix examples, see
5+
[CI_CACHING.md](CI_CACHING.md). For the composite action inputs and outputs, see
6+
[`.github/actions/setup/README.md`](../.github/actions/setup/README.md).
7+
8+
## What to cache
9+
10+
Cache these paths together with a key that identifies the runner, fbuild build,
11+
board, and build-graph inputs:
12+
13+
| Path | Why it matters |
14+
|---|---|
15+
| `FBUILD_CACHE_DIR` | fbuild's package cache: downloaded archives, extracted toolchains/frameworks/libraries, and `index.sqlite`. The setup action pins this to `$RUNNER_TEMP/fbuild-cache`. |
16+
| `$ZCCACHE_DIR` | zccache's compiled-object store. This is required for cross-run per-translation-unit reuse. |
17+
| `.fbuild/build` | Project build outputs and fingerprints. This is what lets a second build become a near no-op when inputs have not changed. |
18+
19+
Do not cache `~/.fbuild/*/daemon/`. It contains runtime-only PID, port, log,
20+
and status files for a daemon that will not exist in the next CI run.
21+
22+
## Key composition
23+
24+
For a single board on one pinned runner image, compose keys from:
25+
26+
1. Cache schema version: a manual `v1`, `v2`, or date-stamped bump.
27+
2. Runner identity: the fixed image label plus `${{ runner.os }}-${{ runner.arch }}`.
28+
3. Installed fbuild content hash: use the setup action's `fbuild-hash` output.
29+
4. Board or environment name: for example `esp32dev`.
30+
5. Build-graph inputs: `platformio.ini`, board JSON, lock files, toolchain pins, or any file that changes libraries/frameworks/build flags.
31+
32+
The fbuild content hash is important. Version strings alone do not protect
33+
against local installs, dev builds, or a wheel re-uploaded with the same version.
34+
The setup action computes the hash for you and uses it in its built-in
35+
`FBUILD_CACHE_DIR` cache key.
36+
37+
## Invalidation pattern
38+
39+
Keep normal invalidation automatic by hashing graph inputs. Keep forced
40+
invalidation explicit by carrying a manual cache version in workflow `env`:
41+
42+
```yaml
43+
env:
44+
FBUILD_CACHE_VERSION: v1
45+
```
46+
47+
Bump that value when you change runner images, alter cache layout assumptions,
48+
or suspect a poisoned cache. If you use the setup action's built-in cache, pass
49+
the same value to `cache-version` so both fbuild's package cache and your
50+
consumer-managed zccache/build-output cache roll together.
51+
52+
## Copy-paste GitHub Actions block
53+
54+
This example is for one board on one pinned runner image. It lets the setup
55+
action cache fbuild's package/tool cache, then adds a second cache entry for
56+
zccache and project build outputs.
57+
58+
```yaml
59+
jobs:
60+
build:
61+
runs-on: ubuntu-24.04
62+
env:
63+
FBUILD_BOARD: esp32dev
64+
FBUILD_RUNNER_IMAGE: ubuntu-24.04
65+
FBUILD_CACHE_VERSION: v1
66+
steps:
67+
- uses: actions/checkout@v4
68+
69+
- name: Setup fbuild
70+
id: fbuild
71+
uses: FastLED/fbuild/.github/actions/setup@main
72+
with:
73+
cache-version: ${{ env.FBUILD_CACHE_VERSION }}
74+
cache-key-extra: ${{ env.FBUILD_RUNNER_IMAGE }}-${{ env.FBUILD_BOARD }}-${{ hashFiles('platformio.ini', 'rust-toolchain.toml', '.fbuild-cache-version') }}
75+
76+
- name: Restore zccache store and fbuild build outputs
77+
uses: actions/cache@v4
78+
with:
79+
path: |
80+
${{ steps.fbuild.outputs.zccache-store-path }}
81+
.fbuild/build
82+
key: zccache-${{ env.FBUILD_CACHE_VERSION }}-${{ env.FBUILD_RUNNER_IMAGE }}-${{ runner.os }}-${{ runner.arch }}-${{ steps.fbuild.outputs.fbuild-hash }}-${{ env.FBUILD_BOARD }}-${{ hashFiles('platformio.ini', 'rust-toolchain.toml', '.fbuild-cache-version') }}
83+
restore-keys: |
84+
zccache-${{ env.FBUILD_CACHE_VERSION }}-${{ env.FBUILD_RUNNER_IMAGE }}-${{ runner.os }}-${{ runner.arch }}-${{ steps.fbuild.outputs.fbuild-hash }}-${{ env.FBUILD_BOARD }}-
85+
zccache-${{ env.FBUILD_CACHE_VERSION }}-${{ env.FBUILD_RUNNER_IMAGE }}-${{ runner.os }}-${{ runner.arch }}-${{ steps.fbuild.outputs.fbuild-hash }}-
86+
zccache-${{ env.FBUILD_CACHE_VERSION }}-${{ env.FBUILD_RUNNER_IMAGE }}-${{ runner.os }}-${{ runner.arch }}-
87+
88+
- name: Build
89+
run: fbuild build examples/Blink -e "$FBUILD_BOARD"
90+
```
91+
92+
Adjust the `hashFiles(...)` list to match your repository. If your board list,
93+
library pins, or build flags live somewhere else, include those files in the
94+
hash.
95+
96+
## Expected numbers
97+
98+
Use these as order-of-magnitude expectations, not hard pass/fail thresholds.
99+
[CI_CACHING.md](CI_CACHING.md#expected-timings) has the current CI-oriented
100+
summary; [PERF_WARM_BUILD.md](PERF_WARM_BUILD.md) records the local profiling
101+
context behind the warm-path work.
102+
103+
| Scenario | Observed shape |
104+
|---|---|
105+
| First cache-miss ESP32 build | Can be dominated by downloads and full framework compile; the local benchmark saw about 14 minutes on Windows for `tests/platform/esp32dev`. |
106+
| Warm small AVR build | About 250 ms wall-clock in the local benchmark once disk cache and build outputs were populated. |
107+
| Steady-state warm ESP32 build | About 280 ms wall-clock for runs 3+ with the same daemon. |
108+
| Current CI warm no-op target | Near-warm builds should be single-digit seconds including CLI and daemon overhead; the internal hot path can be much lower. |
109+
110+
CI cache restore should remove package download and extraction time. It does not
111+
guarantee every restored build is as fast as a hot-daemon local no-op, especially
112+
for ESP32 paths that still need warm-path validation. A restored build that still
113+
downloads toolchains or frameworks usually means the package cache key/path is
114+
wrong; a restored build that skips downloads but spends time validating project
115+
outputs points at warm-path behavior instead.
116+
117+
## Common pitfalls
118+
119+
- Caching `~/.fbuild/prod/` wholesale restores daemon state. Cache
120+
`FBUILD_CACHE_DIR` instead.
121+
- Sharing one key across OSes, architectures, or runner images can restore
122+
incompatible toolchains or path-embedded response files.
123+
- Keying only on `platformio.ini` can miss board JSON, lock file, or toolchain
124+
changes that should invalidate stale outputs.
125+
- Omitting `fbuild-hash` can keep stale artifacts after an fbuild upgrade or dev
126+
build change.
127+
- Restoring zccache without `.fbuild/build` still helps compile reuse, but it
128+
will not preserve fbuild's project-level warm-build fast path.
129+
- Letting cache entries grow past GitHub Actions limits can make saves fail. If
130+
needed, cap fbuild's package cache with `FBUILD_CACHE_BUDGET=8G`.
131+
132+
## See also
133+
134+
- [CI_CACHING.md](CI_CACHING.md) - detailed cache design, raw snippets, and
135+
matrix guidance.
136+
- [`.github/actions/setup/README.md`](../.github/actions/setup/README.md) -
137+
setup action contract and examples.
138+
- [PERF_WARM_BUILD.md](PERF_WARM_BUILD.md) - benchmark context behind the
139+
expected warm-build numbers.

docs/CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ For a full FAQ-style index of every doc in this repo (human + LLM entry point),
2626
- **[WHY.md](WHY.md)** - Why fbuild exists, key benefits, performance
2727
- **[BOARD_STATUS.md](BOARD_STATUS.md)** - Per-platform CI badges and supported boards
2828
- **[DEVELOPMENT.md](DEVELOPMENT.md)** - Testing, troubleshooting, local setup
29+
- **[CI_CACHE.md](CI_CACHE.md)** - Consumer-facing cross-run CI cache strategy
2930
- **[DESIGN_DECISIONS.md](DESIGN_DECISIONS.md)** - ADR-style decisions with rationale
3031
- **[ROADMAP.md](ROADMAP.md)** - Implementation phases
3132
- **[ARCHITECTURE.md](ARCHITECTURE.md)** - Index of all architecture documents

docs/INDEX.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ A grep-friendly FAQ that maps common questions to the file that answers them. Bo
2323
| How do I run tests / lint / fmt? | [DEVELOPMENT.md](DEVELOPMENT.md#testing) |
2424
| Why is my build failing? | [DEVELOPMENT.md](DEVELOPMENT.md#troubleshooting) |
2525
| How do I use the emulator (QEMU / avr8js / simavr)? | [../README.md](../README.md#emulator-testing) |
26+
| What CI cache block should consumers copy? | [CI_CACHE.md](CI_CACHE.md#copy-paste-github-actions-block) |
27+
| What cache keys and invalidation pattern should CI use? | [CI_CACHE.md](CI_CACHE.md#key-composition) |
2628
| How do I cache fbuild across CI runs? | [CI_CACHING.md](CI_CACHING.md) |
2729
| What's safe to cache in GitHub Actions? | [CI_CACHING.md](CI_CACHING.md#what-the-cache-holds) |
2830
| Why does warm-pass build take ~30 s per sketch? (#91) | [PERF_WARM_BUILD.md](PERF_WARM_BUILD.md) |

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Architecture and design documentation for the fbuild project.
1010
- **`WHY.md`** -- Why fbuild exists, key benefits, performance benchmarks
1111
- **`BOARD_STATUS.md`** -- Per-platform CI badges and supported boards
1212
- **`DEVELOPMENT.md`** -- Testing, troubleshooting, local development setup
13+
- **`CI_CACHE.md`** -- Consumer-facing cross-run CI cache strategy
1314
- **`CI_CACHING.md`** -- How to save/restore fbuild's cache across CI runs
1415
- **`DESIGN_DECISIONS.md`** -- ADR-style decisions with rationale
1516
- **`ROADMAP.md`** -- Implementation phases for the Rust port

0 commit comments

Comments
 (0)