# Firefox compile-cache benchmark scenario for kache-scenario.
name     = "bench-firefox"
tags     = ["suite:bench", "project:firefox", "backend:kache", "lang:cc", "lang:cpp", "lang:rust"]

# No `requires`: it's a PATH check for external tools the harness needs
# around the checkout (cf. substrate's cargo/rustc). Firefox's build
# driver is `./mach` IN the source tree, and `./mach bootstrap`
# provisions its own toolchain — so there's nothing to pre-check on PATH.

# One-time toolchain setup. Skipped when ~/.mozbuild already exists
# (--force-setup overrides); the toolchain it installs is shared across runs.
setup        = ["./mach bootstrap --application-choice browser"]
setup_marker = "~/.mozbuild"

build = "./mach build"

[source]
kind   = "clone"
repo   = "https://github.com/mozilla-firefox/firefox.git"
ref    = "FIREFOX_151_0_RELEASE"
objdir = "obj-kache-bench"

# Firefox ships no mozconfig, so we own and write this file. The cc side
# genuinely needs it: --with-compiler-wrapper can't come from env.
[[file]]
path    = "mozconfig"
content = """
# Generated by kache-scenario — compile-cache benchmark.
# Optimized, non-debug, no LTO/PGO: representative of a dev build
# and the fairest workload for a compile cache (LTO would defer
# codegen to link time and shrink the cacheable -c surface; PGO
# would build twice). Drop --disable-tests for a larger workload.
ac_add_options --enable-optimize
ac_add_options --disable-debug
ac_add_options --disable-tests

# Prepend kache as the C/C++ compiler launcher. Firefox keeps
# selecting its own bootstrapped clang; kache wraps each -c step.
#
# --with-compiler-wrapper, NOT --with-ccache: --with-ccache makes
# mozbuild run `<wrapper> -s` for ccache stats at build start, and
# kache rejects `-s` (exit 2) → the build aborts. The wrapper knob
# prepends kache identically but skips that ccache stats probe.
ac_add_options --with-compiler-wrapper={kache}

# Route rustc through kache too (also set on the build env).
mk_add_options "export RUSTC_WRAPPER={kache}"

# Also cache rust bin/dylib/cdylib/proc-macro outputs (off by default
# because executables can bake absolute paths/RPATHs — the out-dir-runtime
# false-hit class). Safe to measure here: the bench's leak detector +
# --negative-control surface any path-baking as a divergence/miss rather
# than a silent wrong-artifact restore.
mk_add_options "export KACHE_CACHE_EXECUTABLES=1"

# Incremental compilation is redundant once a compile cache is in
# play — kache treats it so (it cleans incremental dirs) and
# Firefox itself disables it for sccache/buildcache. Off here keeps
# the objdir lean and removes a measurement-noise source. (Not a
# correctness fix: kache already excludes -Cincremental from the
# cache key.)
mk_add_options "export CARGO_INCREMENTAL=0"

# Per-clone objdir so the two builds never collide.
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/{objdir}

# Cross-clone cache-key portability (the headline metric this bench
# measures). Each clone builds at a different absolute path. ~18
# NSS-linking crates (neqo-crypto, ohttp, gkrust, …) fold an absolute
# `-L <objdir>/security` into their key — emitted by build scripts that
# read mozbuild::TOPOBJDIR — so without normalization they diverge and
# miss across clones.
#
# KACHE_BASE_DIR makes kache rewrite paths under it to a stable
# `<BASE_DIR>` sentinel in the cache key. `@TOPSRCDIR@` expands per
# clone (the objdir lives under it), so each clone normalizes its OWN
# objdir path and the keys line up. This is safe
# here because kache keeps mozbuild's baked objdir as a per-clone key
# discriminator (env_dep / source literal), so each clone builds its
# own mozbuild and its build scripts emit that clone's local path —
# which then normalizes. (A foreign clone's path can only leak in if
# mozbuild itself hit cross-clone, which it does not.)
mk_add_options "export KACHE_BASE_DIR=@TOPSRCDIR@"

# Pin the Firefox build ID so buildid.cpp / application.ini.h are
# byte-identical across clones. Without it they bake the wall-clock build
# time, and the two clones build minutes apart — diverging those 2 TUs.
# This is Firefox's canonical reproducible-build knob (build/variables.py).
mk_add_options "export MOZ_BUILD_DATE=20260101000000"

# Opt these path-only env vars into kache key normalization (the OUT_DIR
# contract): each only locates an `include!()`'d generated file whose
# content is hashed separately, so the absolute value is a pure locator.
# BUILDCONFIG_RS/MOZ_TOPOBJDIR/MOZ_TOPSRCDIR pair with the mozbuild
# path-clean patch; CONVERSIONS_FILE/GLEAN_METRICS_FILE/BINDINGS/
# TYPENUM_BUILD_CONSTS converge crashping/mtu/typenum. Deliberately NOT
# CARGO_MANIFEST_DIR — it is value-baked (#167), normalizing it miscaches.
mk_add_options "export KACHE_PATH_ONLY_ENV_VARS=BUILDCONFIG_RS,MOZ_TOPOBJDIR,MOZ_TOPSRCDIR,CONVERSIONS_FILE,GLEAN_METRICS_FILE,BINDINGS,TYPENUM_BUILD_CONSTS,TYPENUM_BUILD_OP,TYPENUM_BUILD_GENERIC_CONSTS"
"""

# Make mozbuild path-clean so its rlib is byte-identical across checkouts —
# the cross-clone cascade root. env!() macros instead of baked objdir
# literals, drop the TOPOBJDIR/TOPSRCDIR/NSPR/NSS path consts, build scripts
# read MOZ_TOPOBJDIR/MOZ_TOPSRCDIR. The patch also updates the 4 vendored NSS
# crates' .cargo-checksum.json to match their edited build.rs (a bench-only
# necessity — an upstream submission regenerates checksums via `mach vendor`).
# `path` is just a label here; `git apply` reads targets from the diff.
[[file]]
path         = "build/rust/mozbuild/generate_buildconfig.py"
mode         = "patch"
content_file = "patches/firefox-mozbuild-path-clean.patch"

# Make webrender/khronos_api emit include_str!/include_bytes! paths relative to
# OUT_DIR (where the generated .rs lives) instead of absolute, so the generated
# shaders.rs / webgl_exts.rs are byte-identical across checkouts. khronos_api is
# vendored, so the patch also updates its .cargo-checksum.json (bench-only).
[[file]]
path         = "gfx/wr/webrender/build.rs"
mode         = "patch"
content_file = "patches/firefox-generated-source-relative.patch"

[checks.assert.warm]
min_key_stability_pct = 50.0
max_passthrough_pct = 40.0
max_errors = 0
