Skip to content

perf(build): framework libs (~150s) recompiled per project; core cache never hydrates #952

Closed

Description

@zackees

Context

#942 Phase-1 baseline, warm scenario (global cache fully warm, fresh project copy): fw-libs=150.7s re-runs in full for every new project directory even though the framework libraries are identical for a given platform + flag set. The fw-libs fingerprint only short-circuits within the same project (hot = 1 ms).

Related: core-cache-hydrate=0 ms in all 9 baseline runs while compile-core-variant always spends ~11 s and core-cache-store runs afterwards every time — i.e. the global core cache is written but apparently never hit, even cold → warm → hot inside one container session.

Proposal

  • Scope the framework-lib artifact cache globally (keyed by platform/toolchain/flag fingerprint) so a fresh project hydrates ~150 s of compiled framework objects, mirroring the package disk cache design.
  • Diagnose and fix the core-variant cache: why store-then-never-hydrate? (key mismatch across builds is the likely culprit.)

Acceptance criteria

Part of #942.

Activity

  1. zackees commented on Jul 5, 2026

    @zackees
    MemberAuthor

    Root cause (diagnosed via the #942 harness)

    Measured on NightDriverStrip esp32 demo, WARM scenario (fresh project dir + fully warm zccache), post-#951/#955 main:

    phase cold warm note
    compile-sketch 90 s 0.66 s zccache HITS across project dirs
    compile-core-variant 11.4 s 0.45 s zccache HITS
    fw-libs 185 s 164 s zccache does NOT hit — full recompile

    So with a warm zccache, sketch and core already collapse to sub-second; the entire warm-scenario cost is fw-libs not hitting zccache. The core-cache hydrate (core-cache-hydrate=0ms) is a secondary issue — irrelevant once zccache is warm, since core-variant hits zccache anyway.

    Why fw-libs misses zccache while sketch/core hit

    The two compile paths construct the invocation differently:

    • sketch + core → crate::compiler::compile_source (crates/fbuild-build/src/compiler.rs:658-711): computes compile_cwd = zccache::compile_cwd_from_output(output) (the workspace root), relativizes source / -o / -I to it (path_arg_for_compile_cwd, normalize_flags_for_compile_cwd), and runs with cwd = workspace. → zccache key is workspace-relative → identical for /tmp/nds and /tmp/nds2 → HIT.
    • fw-libs → library_compiler::compile_one_source (crates/fbuild-packages/src/library/library_compiler.rs:305-397): passes absolute source (:343), -o (:345), and absolute -I (:531) strings, wraps with the legacy zccache wrap binary, and invokes run_command(&args, None, …) — cwd = None (:377). It never calls compile_cwd_from_output / path_arg_for_compile_cwd / normalize_flags_for_compile_cwd. → the zccache key embeds /tmp/nds/... → MISS on every fresh project.

    Fix

    Make fw-lib compiles workspace-relative like sketch/core. Two options:

    1. Route fw-libs through crate::compiler::compile_source (the embedded ZccacheService, standardized in perf(zccache) Phase 4 stage 2: embedded mandatory — delete FBUILD_ZCCACHE_EMBEDDED + wrapper fallback #800) instead of compile_library_with_jobs, then archive the resulting objects. Stays in fbuild-build (ESP32-only blast radius), reuses the proven relativized path.
    2. Relocate the three pure path helpers (compile_cwd_from_output, path_arg_for_compile_cwd, normalize_flags_for_compile_cwd) from fbuild-build/src/zccache.rs to fbuild-core::path (both crates depend on it), then relativize in compile_one_source and pass Some(cwd) to run_command. Fixes it for all platforms' library compiles, but wider blast radius (shared path — warrants full cross-platform CI + Windows path-normalization review, since the helpers carry the ESP32 compile on Windows: 'Cannot create temporary file in C:\Windows\' — uncovered tempfile callsite #875/fix(compile): pin TMP/TEMP for compiler subprocess on Windows (#875) #885/fix(compile): force / in path args so cc1 spec-file pass works on Windows #890/fix(compile): rewrite backslashes on the PIO no-compile-CWD fallback path #912 slash fixes).

    Either way fw-libs drops from ~164 s to seconds with no new archive cache. I attempted a self-contained global archive cache twice; both failed (the cross-project key still differed, and the store didn't write) — the archive cache is the wrong layer. The path-normalization lesson is captured in agents/docs/path-conventions.md (PR #961).

    Secondary follow-up

    core_cache_key still computes a project-varying key even after stripping project -I dirs (an additional project-specific input remains — needs a debug-logged component diff to pinpoint). Low priority: core-variant hits zccache when warm, so the hydrate only matters on a cold-zccache fresh machine, and even then the hydrated .cmdhash (written with the storing project's includes) mismatches the hydrating project's per-TU check. Track separately from the fw-libs fix above.

  2. zackees commented on Jul 5, 2026

    @zackees
    MemberAuthor

    PR #965 lands the necessary first step — fw-libs compiles are now workspace-relative like sketch/core (via opt-in compile_cwd in the shared library compiler; every other caller unchanged). Measured warm fw-libs 185s→141s in the #942 harness. It is NOT the full win: a clean cold→warm shows sketch/core don't fully hit zccache cross-project either, so workspace-relative args are necessary but not sufficient. The remaining payoff is tracked in #966 (firmware-compile zccache cross-project key stability). Keeping #952 open until #966 lands the sub-second warm fw-libs.

  3. zackees commented on Jul 7, 2026

    @zackees
    MemberAuthor

    Closing this tracker as split/resolved.

    The warm fresh-project fw-libs target is resolved by #987/#986: the #942 harness result in #987 shows warm fw-libs dropping from 152s to 2.2s, with sketch/core/fw-libs all hitting zccache cross-project.

    The bundled core-cache-hydrate concern was not proven fixed; it is now separated into #995 so this broad tracker does not keep mixing the resolved fw-libs bottleneck with a lower-priority cache-path audit.

    Refs #992.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions