Skip to content

Integrate ib_linux / ib_console for distributed Bun builds#1

Open
zozo123 wants to merge 10 commits into
mainfrom
incredibuild/ib-linux-integration
Open

Integrate ib_linux / ib_console for distributed Bun builds#1
zozo123 wants to merge 10 commits into
mainfrom
incredibuild/ib-linux-integration

Conversation

@zozo123
Copy link
Copy Markdown
Collaborator

@zozo123 zozo123 commented May 20, 2026

Summary

Wires Bun's Ninja-driven build through ib_console from Incredibuild-RND/ib_linux so the ~2k C/C++ TUs (boringssl, WebKit when local-built, libuv, libarchive, c-ares, lsquic, mimalloc, …) and the 107-crate Rust workspace can be distributed across an Incredibuild grid.

  • Opt-in everywhere; zero behavioral change unless BUN_USE_INCREDIBUILD=1 or .incredibuild/build.sh is invoked.
  • Buildkite pipeline untouched.
  • New GH Actions workflow gives an end-to-end validation lane. Profile XSD check already passing on ubuntu-latest.

What's in here

File Purpose
.incredibuild/ib_profile.xml clang/clang++/gcc/g++ local_only with exclude_args="-c:-S:-E" (compile distributes, link stays local). ninja/cmake/cargo/bun intercepted recursive so LD_PRELOAD propagates. rustc allow_remote minus build_script_build.
.incredibuild/ib_profile.xsd Vendored from ib_linux/data/ib_profile.xsd so XSD validation works in CI without cross-repo auth to the internal ib_linux repo.
.incredibuild/build.sh One-shot wrapper: ib_console -- bun scripts/build.ts … with env knobs (IB_FORCE_REMOTE, IB_MAX_LOCAL, IB_CONSOLE, IB_PROFILE, IB_CAPTION, IB_EXTRA_ARGS).
.incredibuild/validate.sh xmllint the profile against the XSD.
.incredibuild/README.md Setup, knobs, distributability matrix per phase.
scripts/build.ts 20-line opt-in patch: BUN_USE_INCREDIBUILD=1 and not already wrapped ⇒ wrap the inner ninja spawn with ib_console --profile … --. Touches CI and local spawn sites.
.github/workflows/incredibuild-linux.yml validate-profile-xsd job on ubuntu-latest (runs on every PR) + build job on [self-hosted, linux, incredibuild] (gated on validate).

How it routes work

clang -c foo.cpp matches the exclude_args="-c" exemption on the local_only rule, so it falls through to IB's distribution path. clang foo.o … -o bun (link, no -c) stays pinned to the initiator — LTO needs all objects on one box anyway. rustc is allow_remote except for build_script_build invocations (build.rs scripts that inspect the host). ninja/cmake/bun are intercepted recursive so the LD_PRELOAD interceptor follows the whole child process tree.

Validation already done

Real GitHub Actions (commit 98fa0bd):

  • validate-profile-xsd passes on ubuntu-latest in 25s — xmllint --schema .incredibuild/ib_profile.xsd .incredibuild/ib_profile.xml returns "validates".

Local Linux container (Ubuntu 24.04 + real clang/ninja/bun + stub ib_console that validates against the real XSD):

  • ib_linux's own samples/make_build runs cleanly through the wrapper (30 gcc compiles).
  • 21/21 assertions on the dispatch logic — default path direct ninja; BUN_USE_INCREDIBUILD=1 wraps with full correct argv; BUN_INCREDIBUILD_WRAPPED=1 short-circuits the inner wrap; IB_FORCE_REMOTE and IB_MAX_LOCAL plumbed; .incredibuild/build.sh chains correctly and propagates BUN_INCREDIBUILD_WRAPPED=1.

What still needs hardware

  • Self-hosted Linux runner with ib_linux installed, coordinator-registered, labeled [self-hosted, linux, incredibuild].
  • workflow_dispatch of incredibuild-linux.yml with bun_profile=ci-cpp-only and force_remote=true.
  • Wall-time comparison vs stock bun scripts/build.ts --profile=ci-cpp-only on the same runner.

🤖 Generated with Claude Code

zozo123 and others added 3 commits May 20, 2026 09:53
Wraps the Ninja-driven Bun build with Incredibuild's ib_console so the
~2,000 C/C++ TUs (Bun core + boringssl + WebKit + libuv + libarchive + …)
and 107-crate Rust workspace can be distributed across an IB grid.

- .incredibuild/ib_profile.xml: process intercept/distribution rules.
  clang/clang++/gcc/g++ are local_only with exclude_args="-c:-S:-E" so
  compile-only invocations distribute while link stays local. ninja /
  cmake / cargo / bun are intercepted recursive so LD_PRELOAD propagates
  through the whole subtree. rustc is allow_remote with build_script_build
  excluded (build.rs inspects the host).

- .incredibuild/build.sh: wrapper that runs `ib_console -- bun
  scripts/build.ts …` with sane defaults and BUN_INCREDIBUILD_WRAPPED=1
  to prevent the inner ninja spawn from re-wrapping.

- scripts/build.ts: opt-in BUN_USE_INCREDIBUILD=1 wraps the inner ninja
  spawn with ib_console. No-op when unset or when already wrapped.

- .github/workflows/incredibuild-linux.yml: self-hosted runner workflow
  gated on the [self-hosted, linux, incredibuild] label set.

- .incredibuild/README.md: setup + verification + tunables.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ib_profile.xml comments contained `--` (XML-illegal double-hyphen inside
comments), causing the file to fail libxml2 parsing entirely. Rewrote the
comments to avoid the sequence. The profile now validates clean against
ib_linux/data/ib_profile.xsd — the same XSD the real ib_console uses
internally to load ProfileConfig.

Added .incredibuild/validate.sh: auto-locates the XSD (env var, installed
ib_linux, sibling checkout) and runs xmllint. Anyone can sanity-check the
profile without spinning up a coordinator + helper grid.

incredibuild-linux.yml: new `validate-profile-xsd` job on ubuntu-latest
that fetches the XSD from Incredibuild-RND/ib_linux@develop and validates
the profile on every PR. Gated `build` on `validate` so a broken profile
fails fast instead of consuming a self-hosted runner slot.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The validate-profile-xsd job was fetching the XSD from
Incredibuild-RND/ib_linux at run time, which 404s on ubuntu-latest because
ib_linux is INTERNAL and the workflow's GITHUB_TOKEN doesn't have
cross-repo access.

Vendor data/ib_profile.xsd (97 lines, ~4 KB) into .incredibuild/. The
profile schema is versioned and changes rarely; bumping the vendored copy
when ib_linux releases a new schema is a 1-line diff.

validate.sh now prefers the vendored copy and falls back to env override /
installed ib_linux / sibling checkout. The CI step is now a single
`./.incredibuild/validate.sh` — no network calls, no auth, no flake.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@autofix-troubleshooter
Copy link
Copy Markdown

Hi! I'm the autofix logoautofix.ci troubleshooter bot.

It looks like you correctly set up a CI job that uses the autofix.ci GitHub Action, but the autofix.ci GitHub App has not been installed for this repository. This means that autofix.ci unfortunately does not have the permissions to fix this pull request. If you are the repository owner, please install the app and then restart the CI workflow! 😃

zozo123 and others added 7 commits May 20, 2026 13:24
Extracts the IB invocation into two reusable composite actions and adds
a benchmark workflow so we can measure speedup objectively.

- .github/actions/ib-build/action.yml: single source of truth for
  `ib_console -- bun scripts/build.ts`. Inputs cover profile, force-remote,
  max-local-cores, cache-dir, caption, extra-args. Outputs the log path
  the metrics action consumes.

- .github/actions/ib-metrics/action.yml: parses ib_console's monitor log
  (task counts, local vs helper distribution, cache hits, acceleration
  factor) and writes a markdown table to $GITHUB_STEP_SUMMARY. Falls
  back to placement-line counting if structured fields aren't emitted.

- .github/workflows/incredibuild-linux.yml: wires actions/cache@v4 to
  ib_console's --build-cache-local-user dir (cache key on profile +
  Cargo.lock + package.json + scripts/build/** + build.rs files), uses
  the composite actions, uploads the ib log on every run + build dir on
  failure. Also adds shellcheck of the wrapper scripts to the validate job.

- .github/workflows/incredibuild-compare.yml: manual-dispatch benchmark.
  Builds the same profile N times with and without IB, reports median
  wall time, delta, and speedup factor. Designed as the canonical
  acceleration-regression check.

- .github/actionlint.yaml: registers the `incredibuild` self-hosted label
  so linters don't flag it as a typo.

Local validation:
  actionlint  → exit 0
  shellcheck  → silent (clean) on build.sh + validate.sh
  xmllint     → profile validates against vendored XSD

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pushes to incredibuild/** and PR triggers were queueing ib-build for
the self-hosted runner indefinitely (no runner exists yet on the GH
side). The validate job still auto-runs on every push/PR — that's
where the per-commit signal lives. ib-build is for benchmarks and
explicit kickoff once the runner is online.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The IB integration block had:
  - paired array items on a single line ("--profile", ibProfile,)
  - one-line ternary spanning >120 chars

Both violate the project's prettier config. autofix.ci flagged them on
PR #1; applying its exact suggested diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The vnext-processing-engine runner image
(nscr.io/.../incredibuild-runner:latest) ships an ib-accel PATH shim
that intercepts `ninja`/`cmake`/`cargo` and transparently wraps them
with `ib_console --standalone --build-cache-local-shared
--build-cache-force --build-cache-basedir=$PWD`. So on
`runs-on: incredibuild-runner` we must NOT also call ib_console
ourselves — it would double-wrap and the shim guards
(__IB_NINJA_WRAPPED, IB_CONSOLE_SKIP) would interact badly.

What changed:

- Renamed runner label to `incredibuild-runner` (single descriptive
  label; `self-hosted` is auto-applied by GitHub) — matches vnext's
  JIT pool registration.

- Dropped .github/actions/ib-build/action.yml. The composite action
  existed to do the ib_console wrap, which is now redundant. The
  build.ts opt-in patch + .incredibuild/build.sh remain for off-grid
  use (workstation with ib_linux, traditional self-hosted).

- ib-build job now: cp .incredibuild/ib_profile.xml ib_profile.xml
  (highest-priority slot in ib_console's default load order, since
  the shim invokes ib_console without --profile) → `bun
  scripts/build.ts --profile=…` → done. IB_ACCEL_DEBUG=1 surfaces
  every shim transformation when the workflow_dispatch input is set.

- compare workflow uses IB_CONSOLE_SKIP=1 as the "stock" variant
  (the shim recognizes this and falls back to plain ninja), avoiding
  any divergence between variants other than the wrap itself.

- README documents both paths (vnext runner = default; off-grid =
  set BUN_USE_INCREDIBUILD=1).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Concrete model anchored in measurement, not vibes:

- WHAT: 564 Bun-core TUs + ~1,300 vendored-dep TUs (boringssl 143,
  lsquic 69, libdeflate 11, highway 9, tinycc 6, +200 across array-based
  deps) + 105 Rust crates. Link/ar/strip stay local.

- HOW: vnext runner PATH-shims ninja → ib_console intercepts each
  `clang -c` and ships it to a helper; link stays local. Off-grid uses
  the build.ts opt-in or .incredibuild/build.sh. Same profile both ways.

- BY HOW MUCH: measured T_per_TU = 0.44s on x86_64 clang 18.1.3 (10 vCPU
  container), 5.36x on 10 local cores. Projects to ~24x on a 30-helper
  grid for cpp-only, asymptote ~40x bound by ar/link. Release-LTO is
  Amdahl-bound at link → 5-15x ceiling. Incremental re-runs land at
  5-15s wall via --build-cache-local-shared.

Numbers labeled as derived/projected vs measured; the real
stock-vs-IB delta will come from the incredibuild-compare.yml workflow
once a vnext runner is provisioned.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previous model assumed a remote-helper distribution grid (24x at K=30,
40x asymptote). That's WRONG for this deployment. vnext's ninja shim
hard-codes `ib_console --standalone --build-cache-local-shared
--build-cache-force` (line 65 of src/runner_engine/build/ib-accel/bin/ninja),
so:

- No distribution. Every compile runs locally.
- Acceleration comes entirely from the content-addressed compile cache.
- The cache lives in $PWD via --build-cache-basedir; vnext promotes
  cache/ across JIT pod runs via the /ib-workspace virtiofs mount.

Corrected speedup curve as a function of cache HIT RATE (not helper
count):

  0% hit (cold first build)    -> ~1.0x (~1% hashing overhead)
  50% hit (rebase)             -> ~1.8x
  90% hit (small refactor)     -> ~7x
  99% hit (PR re-push, 1 file) -> ~15x
  100% hit (CI re-run same SHA)-> ~30x  (capped by ar/link)

Per-profile ceilings: debug builds get the most (~30x best case),
ci-release with LTO is bound by uncached link time (5-15x ceiling).

Cold-cache builds get no speedup — that's the honest answer. The
acceleration is a function of the cache hit rate, which is high in
typical CI patterns (PR pushes touching small file sets) and low
after large refactors or compiler upgrades.

Real numbers still need a `gh workflow run incredibuild-compare.yml`
on a vnext runner with the cache pre-warmed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
vnext runs ib_console --standalone, so the distribution narrative was
misleading. README now matches ACCELERATION.md: cache-only, ~1.5k
cacheable TUs, big wins on incremental, ~1x on cold.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants