From fbf8856c1117107ba57fb5c8f1c2cca1176febbe Mon Sep 17 00:00:00 2001 From: brettchien Date: Fri, 14 Aug 2026 23:58:29 +0800 Subject: [PATCH] ci(desktop): cut macOS sidecar build time (cache binary, unpoison rust-cache, opt-level 0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured `bundle-macos` warm run = ~966s in the sidecar step alone, split ~299s in oab-mcp's final codegen + ~600s recompiling the aws-sdk dep tree *under a cache "hit"*. Three fixes: 1. Content-address the built sidecar binary (actions/cache keyed on crates/** + Cargo.lock + Cargo.toml). Rust-unchanged PRs (the common case — most iterations only touch console/** TS) restore the binary and skip the whole `cargo build`: ~966s -> ~0s. 2. Unpoison rust-cache: the v1 target-dir cache kept reporting "Cache up-to-date" while its saved target had already been pruned of the release-ci deps, so every warm run recompiled the aws-sdk tree. Bump prefix-key v2 (one-time reset), cache-all-crates (keep the deps in the saved target), and save-if main-only (PRs restore a clean main-built cache instead of each minting its own half-empty immutable key). 3. release-ci opt-level 1 -> 0: the sidecar is I/O-bound (AWS calls, no hot loops); opt-level is the only remaining codegen lever with lto/debug already off. Trims oab-mcp's ~299s final codegen. Shipped binary is larger/slower but functionally invisible for this tool. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/desktop.yml | 33 ++++++++++++++++++++++++++++++--- Cargo.toml | 10 ++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml index 8a70765..21aeb2e 100644 --- a/.github/workflows/desktop.yml +++ b/.github/workflows/desktop.yml @@ -57,17 +57,44 @@ jobs: # key matched, the post step said "Cache up-to-date" and saved nothing # (GitHub keys are immutable) — so the release-ci deps never persisted. # - # prefix-key bump = one-time reset off the poisoned v0 cache. # key: hashFiles('Cargo.toml') folds the profile-defining manifest into # the cache key, so any future profile edit auto-mints a fresh key and # self-heals — no need to remember to bump prefix-key by hand again. - prefix-key: "v1-rust" + # + # But that self-heal never actually kicked in on v1: measured warm runs + # still recompiled the whole aws-sdk tree (~600s) under a cache "hit", + # because a PR that first mints a key SAVES a target that rust-cache has + # already pruned of the release-ci deps — and every later run with the + # same Cargo.{toml,lock} hits that immutable, half-empty key and can only + # report "Cache up-to-date". Two fixes: + # - prefix-key v2 = one-time reset off the poisoned v1 cache. + # - cache-all-crates keeps the aws-sdk deps in the saved target. + # - save-if main-only: only `main` writes the cache, so PRs restore a + # clean main-built cache instead of each minting its own half-empty, + # immutable key (the standard rust-cache anti-PR-pollution pattern). + prefix-key: "v2-rust" key: ${{ hashFiles('Cargo.toml') }} + cache-all-crates: "true" + save-if: ${{ github.ref == 'refs/heads/main' }} workspaces: | . -> target src-tauri -> target + # Content-address the built sidecar itself: most PR iterations only touch + # console/** (TS) and never the Rust, yet each still recompiled oab-mcp cold + # (~16m warm). Key on everything that determines the binary — the crate + # sources, the lockfile, and the profile-defining root manifest — so a run + # whose Rust is unchanged restores the binary and skips the build entirely. + # A single small file keyed on its inputs never collides with an immutable + # key (unlike the target-dir cache above), so this can't self-poison. + - name: Cache oab-mcp sidecar binary + id: sidecar-bin + uses: actions/cache@v4 + with: + path: src-tauri/binaries/oab-mcp-aarch64-apple-darwin + key: sidecar-aarch64-apple-darwin-${{ hashFiles('crates/**', 'Cargo.lock', 'Cargo.toml', 'rust-toolchain*') }} - name: Build oab-mcp sidecar (arm64) - # release-ci profile (root Cargo.toml): opt-level 1 + codegen-units 256, + if: steps.sidecar-bin.outputs.cache-hit != 'true' + # release-ci profile (root Cargo.toml): opt-level 0 + codegen-units 256, # so the aws-sdk/aws-lc-sys tree compiles in minutes, not ~23. The sidecar # is I/O-bound (AWS API calls), so it doesn't need full release opt. run: | diff --git a/Cargo.toml b/Cargo.toml index 89e2578..361b1a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,14 @@ resolver = "2" # Fast profile for the CI-built `oab-mcp` sidecar (desktop.yml). The sidecar is an # MCP server that shells out to AWS — it is I/O-bound with no hot loops, so it does -# not need full `release` optimization. Dropping to opt-level 1 + max codegen-units -# turns a ~23-min release compile of the aws-sdk/aws-lc-sys tree into a few minutes; -# the shipped binary is a touch larger/slower but functionally identical. +# not need any optimization. opt-level 0 + max codegen-units minimises codegen: the +# measured cost of a warm sidecar build was ~299s in oab-mcp's own final codegen +# (monomorphising the aws-sdk generics) on top of the dep tree, and opt-level is the +# only remaining lever once lto/debug are already off. The shipped binary is larger +# and a touch slower, but for an I/O-bound tool that's functionally invisible. [profile.release-ci] inherits = "release" -opt-level = 1 +opt-level = 0 codegen-units = 256 lto = false debug = false