Skip to content

bench-incremental: add nix-dynamic tools (experimental builder)#128

Open
aldoborrero wants to merge 5 commits intomainfrom
aldo/bench-incremental-dynamic-v3
Open

bench-incremental: add nix-dynamic tools (experimental builder)#128
aldoborrero wants to merge 5 commits intomainfrom
aldo/bench-incremental-dynamic-v3

Conversation

@aldoborrero
Copy link
Copy Markdown
Member

Supersedes #124 (rebased onto main with #125/#127 merged; force-push avoided by opening fresh).

Adds nix-dynamic / nix-dynamic-nocgo tools to bench-incremental for measuring the experimental builder (buildGoApplicationExperimental, dynamic-derivations + recursive-nix + ca-derivations) against dag mode.

  • dynExprTemplate calling buildGoApplicationExperimental via a pkgs.runCommand wrapper
  • buildTool interface gains SkipOnFail() bool; dynamic tools set it so a missing recursive-nix store SKIPs cleanly instead of aborting the run
  • Dynamic tools run against the host store (not the rooted local?root=... store) — the recursive-nix inner daemon needs the FOD inputDrvs visible
  • nix/dynamic/default.nix: cap --nix-jobs at $NIX_BUILD_CORES so the inner FOD builds don't OOM at NumCPU×2 parallelism
  • docs updated

Verified: --fixture torture --tools nix-dynamic --runs 1 --scenario no_changeOK nix-dynamic / 1.06s. Full torture comparison (nix-ca vs nix-dynamic): dynamic wins no_change ~1.5× (saves the derivationStrict eval floor); dag wins all touch scenarios ~1.8× (no iface cutoff in dynamic — deep is 18 drvs vs 2 — and the wrapper drv reruns go list+drv-gen ~10s/touch).

Adds nix-dynamic and nix-dynamic-nocgo as buildTool entries that build
via buildGoApplicationExperimental (recursive-nix + dynamic-derivations
+ ca-derivations). The harness probes each tool once at startup and
drops a tool with a SKIP notice if its probe build fails — so the
dynamic tools degrade gracefully on stores without recursive-nix while
the rest of the run continues.

writeNixExpr now takes the template as an argument so the dag and
experimental templates share the same path.

:house: Remote-Dev: homespace
The recursive-nix inner daemon serves the same store the outer build
runs against. With NIX_REMOTE=local?root=..., the inner go2nix resolve
registers FOD drvs whose inputDrvs aren't all present in the rooted
store, so AddToStore fails with "path '...' is not valid". The host
store has them (it's where the bench resolved nixpkgs/go2nix-cli from).

Dynamic builds are still per-fixture-path so concurrent runs don't
interfere; the dag tools keep using the rooted store for isolation.

:house: Remote-Dev: homespace
The default (NumCPU*2) launched 128 parallel FOD builds inside the
recursive-nix sandbox on a 64-core host; one got OOM-killed. Honour
the cores budget the outer build was given.

:house: Remote-Dev: homespace
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Benchmark Regression Check

Scenario Tool Base (s) Current (s) Change Drvs (base) Drvs (curr) Status
no_change nix-ca-nocgo 0.69 0.68 -2.2% 0 0 ok
no_change nix-nocgo 0.70 0.68 -3.0% 0 0 ok
leaf-private nix-ca-nocgo 2.61 2.65 +1.5% 2 2 ok
leaf-private nix-nocgo 1.77 1.82 +3.1% 2 2 ok
mid-private nix-ca-nocgo 2.76 2.82 +2.3% 2 2 ok
mid-private nix-nocgo 1.98 3.34 +68.6% 4 4 REGRESSION (time)
deep-private nix-ca-nocgo 3.41 2.95 -13.4% 3 3 ok
deep-private nix-nocgo 2.24 2.16 -3.8% 8 8 ok

Baseline: main | Current: 32989b1ad7c2c2429363bcea07e7fd609b5802ee

Bazel's cc_configure repository rule searches PATH for gcc during
workspace loading.  The bench-incremental wrapper only had nix and
bazel on PATH, so the auto-configuration failed with:

  Cannot find gcc or CC

Add pkgs.stdenv.cc (the wrapped compiler with correct Nix store
include/library paths and binutils) so cc_configure can detect the
host C toolchain.  The recorded absolute paths work correctly with
--incompatible_strict_action_env since build actions use those paths
directly, not PATH lookups.
Bazel creates convenience symlinks (bazel-bin, bazel-out, etc.) in
the workspace directory during builds.  Since the bazel tool shares
fixtureCopy with the nix tools, these symlinks change the store path
when nix-dynamic re-evaluates the fixture, forcing a full wrapper
rebuild that fails with "path is not valid" in the recursive-nix
inner daemon.

Redirect symlinks to the output base via --symlink_prefix so bazel
leaves the shared fixture copy unmodified.
@brianmcgee
Copy link
Copy Markdown
Member

There still appears to be a non-deterministic failure happening regardless of the combination of tools when using the torture fixture:

❯ nix run .\#bench-incremental -- --tools nix-dynamic,nix-dynamic-nocgo,bazel --fixture torture --runs 5 --json comparison.json
Resolving Nix dependencies...
Probing tools...
  OK   nix-dynamic
  OK   nix-dynamic-nocgo
  OK   bazel

======================================================================
INCREMENTAL BUILD BENCHMARK
======================================================================
Fixture:    torture-project/app-full
Tools:      nix-dynamic, nix-dynamic-nocgo, bazel
Touch mode: private
Runs:       5

============================================================
SCENARIO: no-change (cache validation overhead)
============================================================
  Warming caches...

  Run 1/5:
    [nix-dynamic] 1.11s (eval 1.01s + build 0.10s) -- 0 drvs built
    [nix-dynamic-nocgo] 1.12s (eval 1.02s + build 0.10s) -- 0 drvs built
    [bazel] 0.35s (eval 0.14s + build 0.20s) -- 1 drvs built

  Run 2/5:
    [nix-dynamic] 1.12s (eval 1.02s + build 0.10s) -- 0 drvs built
    [nix-dynamic-nocgo] 1.18s (eval 1.08s + build 0.10s) -- 0 drvs built
    [bazel] 0.34s (eval 0.13s + build 0.21s) -- 1 drvs built

  Run 3/5:
    [nix-dynamic] 1.12s (eval 1.02s + build 0.10s) -- 0 drvs built
    [nix-dynamic-nocgo] 1.12s (eval 1.02s + build 0.10s) -- 0 drvs built
    [bazel] 0.39s (eval 0.20s + build 0.19s) -- 1 drvs built

  Run 4/5:
    [nix-dynamic] 1.12s (eval 1.02s + build 0.10s) -- 0 drvs built
    [nix-dynamic-nocgo] 1.16s (eval 1.05s + build 0.11s) -- 0 drvs built
    [bazel] 0.36s (eval 0.16s + build 0.20s) -- 1 drvs built

  Run 5/5:
    [nix-dynamic] 1.09s (eval 1.00s + build 0.10s) -- 0 drvs built
    [nix-dynamic-nocgo] 1.11s (eval 1.01s + build 0.10s) -- 0 drvs built
    [bazel] 0.34s (eval 0.16s + build 0.19s) -- 1 drvs built

============================================================
SCENARIO: leaf (private) -- touch app-full/cmd/app-full/main.go
============================================================
  Warming caches...

  Run 1/5:
  FATAL: build failed for nix-dynamic: nix-store --realise failed: exit status 1
.drv\x1b[0m' is not valid"
       For full logs, run:
         nix log /nix/store/r8bfn72ahbyzi2j2p6xdaxd843ly852m-bench.drv.drv
error: build of resolved derivation '/nix/store/r8bfn72ahbyzi2j2p6xdaxd843ly852m-bench.drv.drv' failed
error: failed to obtain derivation of '/nix/store/8gzp8bi0m1ss5ji8j3x40f4fj8yqkpl2-bench.drv.drv^out'
error: Cannot build '/nix/store/3d1ww1z4z6jb2lfh8an4qn5hgk21wqxq-bench-dynamic.drv'.
       Reason: 1 dependency failed.
error: Build failed due to failed dependency

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