Skip to content

ci: one cross-build runner per target, one target per OS on PRs - #951

Open
u9g wants to merge 5 commits into
mainfrom
jason/cross-build-matrix
Open

ci: one cross-build runner per target, one target per OS on PRs#951
u9g wants to merge 5 commits into
mainfrom
jason/cross-build-matrix

Conversation

@u9g

@u9g u9g commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

The Cross-build linux+windows (zig) job takes ~19 minutes, ~17 of which are a single GoReleaser snapshot build step. It compiles all four zig cross targets in one goreleaser invocation on one ubuntu-latest (4 vCPU) runner:

  • 445 .cc/.c under pkg/apm + 114 under pkg/portaudio ≈ 560 translation units
  • × 4 targets = ~2,240 C++ compiles at -O2 through zig cc
  • 17 min × 4 cores ÷ 4 targets ≈ 1.8 s/TU — a cold WebRTC APM build, every run

Nothing is reused between runs either: setup-go's cache key is an exact go.sum hash with no restore-keys, and even when it hits (699 MB restored in run 33115504417) the step still took 19m19s vs 19m45s cold.

This PR does the cheap structural half:

  1. Matrix the four targets so each gets its own runner instead of sharing 4 vCPUs. Same total CPU, ~4× less wall clock.
  2. Build one target per OS on PRs (lk-linux-amd64, lk-windows-amd64); pushes to main still build all four, so nothing reaches a release untested.

The .cross cache key gains the target id, since each runner now populates only its own .cross/<target>/.

Expected: ~19 min → ~5 min on PRs.

Not addressed here: why a warm 699 MB GOCACHE buys nothing. Worth a follow-up.

u9g added 5 commits August 28, 2026 14:49
The single cross-build job compiled all four zig targets in one goreleaser
invocation on one 4-vCPU runner: ~560 C/C++ translation units (webrtc APM +
portaudio) x 4 targets, ~17 minutes of the job's ~19.

Split into a matrix so each target gets its own runner, and drop the arm64
targets on pull requests -- main still builds all four before release.
setup-go's default key is setup-go-<os>-<arch>-<image>-go-<ver>-<hash(go.sum)>,
with no workflow or job component, so cross-build and the Go Test workflow
compete for one key. Test wins -- cross-build's post step spends 61s tarring
700MB and then reports:

  Failed to save: Unable to reserve cache with key setup-go-Linux-x64-ubuntu24-
  go-1.26.3-d55f71f0...

So the zig cross objects are never stored, and what cross-build restores each
run is Test's native-gcc `go test -race` cache, which no zig target can use:
a 706MB restore that changed the build from 19m45s to 19m19s.

Scope the cache per target with a restore-keys prefix so a go.sum bump keeps
the webrtc/portaudio C++ objects.
Both jobs hit the same setup-go key collision as cross-build: the key has no
workflow or job component, so test.yaml claims it first and these jobs restore
objects they can't use -- native-gcc for the zig Windows cross-build, `-race`
for the darwin build.

windows.yaml's cross-build recompiles the same ~560 webrtc/portaudio TUs plus
a test binary per package at 6m12s a run, and runs twice per push.

@rektdeckard rektdeckard left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I think we can live with ARM build tests only on main

${{ case(
github.event_name == 'pull_request',
fromJSON('["lk-linux-amd64", "lk-windows-amd64"]'),
fromJSON('["lk-linux-amd64", "lk-linux-arm64", "lk-windows-amd64", "lk-windows-arm64"]')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARM builds only happen on merge to main then? I suppose that's OK since these take the lion's share of the time on PRs, but we do lose some confidence.

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.

2 participants