PGO build for releases - #38161
Draft
def- wants to merge 1 commit into
Draft
Conversation
def-
force-pushed
the
pgo-build
branch
6 times, most recently
from
August 11, 2026 21:33
33bac2f to
51ea2b4
Compare
Add a driver for building PGO-optimized environmentd and clusterd:
bin/pgo-build instrument
<run a representative workload against the instrumented binaries>
bin/pgo-build optimize
Measured on a sqllogictest workload, PGO is worth about 6% on the
workload it trained on and about 10% on a disjoint held-out one, for one
extra full build (roughly 17 minutes) at a peak of about 19 GB, which
fits an ordinary CI runner.
Setting RUSTFLAGS makes cargo ignore the rustflags in
.cargo/config.toml, so the script replicates the applicable flags from
there and appends the PGO flags, instead of duplicating the flag lists
the way xcompile.py and ci-builder do. Builds go to a dedicated
target-pgo/ directory to leave the normal incremental cache alone, and
an explicit --target keeps build scripts and proc macros
uninstrumented.
doc/developer/pgo.md covers the constraint that decides whether a
training run is usable at all.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a driver for building PGO-optimized
environmentdandclusterd, plus theone product change PGO needs before it can collect a usable profile.
Nothing is enabled by default. This is the tooling and the enabler, so the win
can be reproduced and a CI integration argued separately.
Why
Measured on a sqllogictest workload (3371 assertions for training, a disjoint
2453-assertion held-out set), PGO is worth about 6% on the training workload
and about 10% on the held-out one, winning all 8 paired interleaved rounds.
The cost is one extra full build, roughly 17 minutes at a peak of about 19 GB,
which fits an ordinary CI runner.
For comparison,
lto = "fat"measured on the same workload gave only 1-3% andneeded an 82 GB link that the OOM killer took on a 125 GB machine. PGO is much
the better trade.
The part that is easy to get wrong
Only a process that exits through its exit handlers writes a usable profile.
Cluster replicas never did, so a training run profiled the parent process and
nothing else, which is a small share of the work: roughly 85% of CPU in this
workload is in the replicas. And a binary built with
-Cprofile-usebut noprofile data is worse than one left alone, because LLVM treats every function
in it as cold.
Two things fix that, and both are required:
clusterdhandles SIGTERM by exiting normally, compiled in only under--cfg pgo_instrument, whichbin/pgo-buildsets for the instrumented buildalone. Production shutdown behavior is unchanged.
--orchestrator-process-wrapper=env, becausesend_sigterminmz_orchestrator_processis!command_wrapper.is_empty(),so with no wrapper the orchestrator goes straight to SIGKILL, which cannot be
caught.
optimizewarns when it finds fewer profile pools than binaries, since thatfailure is otherwise silent.
Testing
No automated tests: this is a build driver, and the product change is
#[cfg]-gated out of every normal build. Verified
cargo check -p mz-clusterdbothwith and without
--cfg pgo_instrument(only the latter type-checks the newcode, and it caught a
function_casts_as_integerwarning that would otherwisehave reached CI), plus
bin/lint-cargoandbin/fmt. Ran the full pipelineend to end on Linux and confirmed one profile merge pool per instrumented
binary.
BOLT
doc/developer/pgo.mdrecords the BOLT evaluation rather than shipping it.BOLT does work on top of this, but only after three non-obvious fixes:
restricting it to Rust symbols with
--funcs=^_R.*(it cannot reconstruct jumptables in OpenSSL, librdkafka, protobuf or abseil), dropping
--update-debug-sections(45+ minutes per binary against 2m31s, thanks todebug = 2), and staging instrumented binaries as real files rather thansymlinks (the orchestrator resolves replicas relative to
current_exe(), whichresolves symlinks, so it silently runs the uninstrumented
clusterd). With allthat, BOLT adds about 1.3% for roughly 12 more minutes of build and the loss of
core-dump analysis. Written down so nobody re-derives it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Cx3DneVrmS4JYNGmYzbUs7