Skip to content

perf(covgate): instrument the build-cache pre-warm#36

Merged
ben-miru merged 1 commit into
mainfrom
perf/covgate-instrumented-prewarm
Jun 25, 2026
Merged

perf(covgate): instrument the build-cache pre-warm#36
ben-miru merged 1 commit into
mainfrom
perf/covgate-instrumented-prewarm

Conversation

@ben-miru

Copy link
Copy Markdown
Contributor

What

Make covgate's build-cache pre-warm instrumented, matching what the coverage runs actually compile. Two passes instead of one plain pass:

  • cover paths (the measured packages): go test -run=^$ -cover <pkgs>-cover defaults to instrumenting each package for itself, matching covgate's per-package -coverpkg=<pkg>.
  • plain paths (the ./tests/... dirs): go test -run=^$ <dirs> — covgate compiles integration test packages as plain deps, so these stay non-instrumented.

Why

The pre-warm compiled non-instrumented test binaries; covgate's coverage runs compile instrumented ones. The saved build cache therefore stored both artifact sets — in production (backend) the gobuild-test cache roughly doubled (~2.2 GB → ~4.3 GB), which pushed the repo back over the 10 GB Actions cache quota (re-triggering LRU eviction → colder restores → high run-to-run variance), and the warm output was only partly reused by the instrumented runs.

Instrumenting the warm pass so it produces the same objects covgate consumes should let the cache hold ~one artifact set and let covgate reuse the pre-warmed instrumented objects instead of rebuilding them.

Prototype — what to measure

This is a prototype; the proof is a backend CI run once this is released and bumped:

  • gobuild-test cache size should fall back toward ~2.2 GB (the headline metric — resolves the quota regression).
  • Cache restore time should drop with the smaller cache.
  • Cold-run penalty (pre-warm + covgate on a cache-cold PR) should ease, since covgate reuses more.
    If the cache doesn't shrink meaningfully, revert — the plain pre-warm is simpler.

Tests / validation

  • PrewarmBuild tests updated to the two-arg form (empty/empty → nil; build error in either pass propagates).
  • collectWarmPaths split tested: cover = measured pkgs, plain = de-duplicated ./tests/... dirs.
  • Existing no-op prewarm seams updated to func([]string, []string) error.
  • go build, go vet, go test, repo lint, and the covgate self-gate (covgate 100%, gocover 93.8%) all pass; no .covgate floors lowered.

Gate (parallelism > 1 && len(pkgs) > 1), the pre-warm duration logging (v0.2.1), and "Total time" semantics are unchanged.

🤖 Generated with Claude Code

The pre-warm compiled non-instrumented test binaries, but covgate's
coverage runs compile instrumented ones (-coverpkg). Storing both sets
roughly doubled the saved build cache downstream (~2.2GB -> ~4.3GB),
reintroducing cache-quota eviction, and the warm output was only partly
reused by the instrumented coverage runs.

Split the warm into two passes that match what covgate actually builds:
- cover paths (the measured packages): `go test -run=^$ -cover <pkgs>`,
  instrumenting each package for itself just as covgate's per-package
  -coverpkg does, so the instrumented objects are reused, not rebuilt.
- plain paths (the ./tests/... dirs): `go test -run=^$ <dirs>`, since
  covgate compiles integration test packages as plain deps.

This should let the cache hold ~one artifact set instead of two and let
covgate reuse the pre-warmed instrumented objects. Gate, logging, and
"Total time" semantics are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ben-miru ben-miru merged commit 794e725 into main Jun 25, 2026
3 checks passed
@ben-miru ben-miru deleted the perf/covgate-instrumented-prewarm branch June 25, 2026 02:51
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