Core Problem
Build tools operate in isolated silos with their own profiling systems. Cargo's --timings and Ninja's logs each show their own performance, but neither reveals the gaps between tools, like the 2.7-second delay before cargo starts after ninja finishes. These inter-tool delays often represent the actual bottlenecks in CI builds but remain invisible to all existing profilers.
The Solution
Buildline merges profiling data from multiple build tools into a single Chrome Trace Event Format timeline, viewable in Perfetto without custom UI development. Rather than using process interception, it wraps each tool invocation individually:
BUILDLINE_SESSION=./build.trace buildline -- ninja
BUILDLINE_SESSION=./build.trace buildline -- cargo build
# open build.trace in https://ui.perfetto.dev
Each wrapper stamps the wall-clock time before executing the tool, reads its profiling artifacts afterward, and appends normalized data to the shared trace file. No orchestration layer is required.
Design Architecture
The Span structure captures build events with relative timestamps, not wall-clock, which lets adapters stay pure functions producing deterministic output suitable for golden-file testing. The wrapper layer alone handles wall-clock offsetting.
Category enforcement uses a closed enum rather than free-form strings. This prevents one adapter from emitting "compile" while another uses "Compile," keeping the merged timeline coherent instead of silently incoherent.
Status variants include "Incomplete" for spans that never finished, which matters for identifying where builds hung or were terminated.
Contribution Model
Adding support for new build systems (Bazel, Gradle, MSBuild) requires only a fixture pair: a real trace artifact and its expected normalized JSON output. CI validates adapters automatically, without a subjective code review.
Current Status
Currently supports Ninja and Cargo, both with golden-file test coverage. Single-machine only for now; distributed builds are out of scope until there's a real answer for clock synchronization. One documented fragility: Cargo's --timings has no stable JSON output, so buildline reads embedded HTML data that could change without notice.
Update (Aug 4): added a fair bit since this went up.
- A webpack adapter (
--profile --json), same golden-file testing as ninja/cargo. - A generic adapter for anything that already writes Chrome Trace Event Format on its own, no dedicated adapter needed. Tested it against real captures from
tsc --generateTraceand Bazel's--profile, which stress it in opposite ways: tsc streams begin/end pairs with real nesting, Bazel writes complete events and never even names its own process. Both fixtures are in the repo. -
CONTRIBUTING.md, since the CLI's error message pointed at a file that didn't exist for two weeks.
Still ninja, cargo, and webpack as dedicated adapters, plus the generic path for anything else. Install/repo links unchanged.
Installation: cargo install buildline
Repository: https://github.com/nabsei/buildline
Crate: https://crates.io/crates/buildline
Top comments (0)