Buildprof
Buildprof shows where the time went in a software build. It traces every process a Linux build launches and turns the recording into an interactive timeline you can explore in the browser.
It works below any individual build system, so the same view can include Cargo crates, Ninja jobs, compiler and linker invocations, shell scripts, code generators, file access, and arbitrary tools launched along the way.
Quick start
On the Linux machine that runs the build:
# Or Homebrew, mise, packages: see Install below.
|
# Your build command after --.
When the build finishes, the recording is saved as output.buildprof and
opens in your browser at buildprof.lalitm.com.
Any build system works; see Build systems.
Nothing is ever uploaded. buildprof.lalitm.com only delivers the UI itself. Your browser fetches the recording from localhost and processes it entirely in the page; no trace data leaves your machine.
Chrome asks once whether buildprof.lalitm.com may access other apps and services on this device. Allow it: that permission is what lets the page fetch the recording from localhost. If you block it, the trace never loads; allow it again under "Local network access" in the site settings next to the address bar.
To see the result without installing anything, open the pre-recorded ripgrep release build in the browser:

Why use Buildprof?
Build tools generally explain only the work they manage themselves. Cargo
timings cannot break down an arbitrary build.rs script; Ninja cannot see
inside commands it launches; compiler traces describe one compiler invocation
rather than the build around it.
Buildprof follows the complete process tree instead. It lets you:
- see where wall-clock time went across the whole build;
- spot work which ran serially, overlapped, or started unexpectedly late;
- inspect full commands, working directories, lifetimes, and exit statuses;
- follow files from the process which produced them to processes which read them;
- use the same profiler with Make, Ninja, CMake, Meson, Cargo, Go, or wrapper scripts; and
- optionally add compiler-internal phases from Clang, LLD, and nightly Rust.
Install
Install on your Linux build machine using whichever method you prefer.
Shell installer:
|
Homebrew:
mise:
Cargo (builds from source; needs Rust 1.91 or newer):
Debian, Ubuntu, Fedora, and other .deb or .rpm distributions: download
the package for your architecture from the
latest release
and install it with apt install ./buildprof_*.deb or
dnf install ./buildprof-*.rpm.
Tarballs: the same release page carries prebuilt binaries for x86_64 and aarch64 Linux, both glibc and static musl.
Usage
Choose another output path or disable automatic opening when needed:
Open an existing recording later with:
Recordings contain command lines and filesystem paths. Review them before sending them to anyone.
Builds on a remote machine
Over SSH there is no browser to launch, so Buildprof prints the port forward to run from your own machine instead and waits for the browser to fetch the trace:
VS Code Remote and JetBrains Gateway forward the port automatically. The wait
gives up after ten minutes; adjust it with --wait <SECONDS>, where 0 waits
forever. Alternatively, copy the recording to your own machine and open it
in the web UI. No local installation is needed
for viewing.
Investigating a slow build? See the investigation guide to find expensive commands, follow their inputs, and inspect compiler phases.
Build systems
Buildprof follows the process tree, so it does not need to understand the build system. These are exercised by the conformance suite on every change:
- Make: compiles, archiving, linking, and renamed outputs.
- CMake with Ninja: the configure step and the Ninja build.
- Meson with Ninja: the setup step and the Ninja build.
- Cargo:
rustcinvocations and linking; nightly self-profile data with--compiler-traces. - Go: compile, assemble, and link.
Anything else that runs as a child process is recorded the same way: shell scripts, code generators, wrapper scripts, and tools launched by the build. Work handed to a daemon or a remote executor happens outside the process tree and is not visible; use local or no-daemon modes where a build system offers them.
Compiler details
Process timing is usually the right level for understanding a build. When a particular compiler or linker invocation needs a closer look, enable compiler tracing:
Buildprof currently imports Clang -ftime-trace, explicitly selected LLD
--time-trace, and nightly Rust self-profile data. These events appear as a
summary of active compiler threads with expandable per-thread phase tracks.
A build which invokes Clang through an absolute path currently bypasses compiler tracing. Buildprof will still record the compiler process, but its Clang and LLD internal phases will be absent.
Compiler tracing can also change compiler cache keys or turn cache hits into misses. Existing Rust compiler wrappers remain in the invocation chain, but cache preservation is not guaranteed in this mode.
Collection options
Process creation, commands and timing are always recorded. File opens and renames are also recorded by default; to reduce overhead on builds with lots of filesystem activity, disable that layer:
The process timeline remains available, but file lists and producer/consumer links are unavailable. This skips filesystem interception itself, rather than collecting and discarding events. The UI identifies recordings made this way.
Compiler-internal tracing is a separate, opt-in layer. It can be combined with process-only recording:
How it works
On Linux, Buildprof launches the command under ptrace and follows process
creation, execution, and exit through the complete descendant tree. A seccomp
filter lets it stop only for the filesystem operations it records instead of
paying the cost of intercepting every system call.
The recorder writes a Perfetto protobuf trace directly. Perfetto provides the storage format, query engine, and core timeline interactions; Buildprof adds the build-specific view on top, including process ancestry, command types, concurrency, file relationships, and optional compiler timing data.
Because recording follows descendants, work delegated to an existing daemon, a remote executor, or another machine is outside the trace. Use local or no-daemon execution modes when a build system provides them.
Backwards compatibility
Before 1.0, the CLI and the UI move in lockstep at the minor version: a recording is meant to be viewed in a UI from the same 0.x series, and patch releases never change the trace format. Every UI version stays deployed under its own path, the CLI opens the one matching its version, and the UI links to the matching series when it is handed a recording from a different one, so nothing stops working, but the trace format may change between minor releases.
From 1.0 onward, the trace format is stable and compatibility is permanent: any recording opens in every later UI, and newer UIs simply add features on top of older recordings.
Self-hosting the UI
Each release attaches buildprof-ui-v<version>.tar.zst, the complete UI as
static files. Serve its contents from any web server and point the CLI at it:
Platform support
Recording builds is currently supported on Linux only. Install Buildprof on the Linux machine that runs your build.
Existing recordings can be viewed on other platforms in the web UI, without installing Buildprof. Viewing a recording does not require the same operating system it was recorded on.
Requirements
- Linux with a kernel or container configuration that permits tracing child
processes: Docker needs
--cap-add SYS_PTRACE,kernel.yama.ptrace_scopemust be below 3, and gVisor-style sandboxes cannot trace at all - Rust 1.91 or newer when installing from source
Development
See CONTRIBUTING.md for the layout and the UI workflow. Run the complete conformance suite in the Linux development container:
For a quick host-side check of formatting, lints, unit tests, and package contents:
License
Licensed under the Apache License, Version 2.0. See LICENSE and AUTHORS.