Profile Guided Optimization
Profile Guided Optimization (PGO) is a compiler feature that uses runtime statistics to make your code run faster, resulting in small performance improvements for your Rust applications.
To use PGO, we first create an instrumented build that collects runtime statistics, then build the final optimized version using those statistics.
Only use PGO if your project outputs binaries.
PGO test cases cannot be easily transferred when your project is included as a dependency via crates.io.
Locally Testing PGO
cargo-pgo makes local testing with PGO easy
Before enabling PGO in CI, you should test it locally to ensure it provides actual performance benefits.
Always Test PGO
PGO isn't guaranteed to always provide an improvement.
After adding representative workloads, always test the results.
Installation
Install globally (one-time setup):
cargo install cargo-pgo
rustup component add llvm-tools-preview
Verify that cargo pgo is installed correctly:
cargo pgo info

Verifying cargo-pgo installation
Testing Workflow
The testing process involves three steps: baseline measurement, profiling collection, and optimized build comparison.
1. Collect Profiling Data
Run an instrumented benchmark to collect profiling data:
cd src
cargo pgo instrument test -- --bench my_benchmark --features pgo
This may also run the regular tests.
2. Run Baseline Benchmark
Establish a performance baseline without PGO:
cd src
cargo bench

Initial benchmark run to establish performance baseline
3. Build with PGO Optimization
Create the PGO-optimized build and compare results:
cd src
cargo pgo optimize bench

Results after running cargo pgo optimize
Evaluating Results
It's normal if some results show a regression. If the overall is a net improvement, keep PGO. Otherwise disable it in CI by setting build-with-pgo: false in your workflow configuration.
Configuring Benchmarks for PGO
PGO works by collecting statistics from representative workloads during benchmark execution. The key is ensuring your benchmarks reflect realistic usage patterns.
Representative Workloads
You should ensure that only realistic representative workloads are used to collect the PGO data.
For example, if this was a compression library, you should run the 'compress' and 'decompress' methods on real files (NOT RANDOM DATA) as part of your benchmarks.
Benchmark Configuration
Two Approaches to PGO Benchmark Configuration
Method 1: Exclude Specific Benchmarks
Update your benchmark code to exclude unrealistic workloads from PGO runs using conditional compilation:
fn criterion_benchmark(c: &mut Criterion) {
// Excluded from PGO.
#[cfg(not(feature = "pgo"))]
{
bench_create_dict(c);
}
}
In this configuration you run your regular benchmarks for PGO, excluding ones that run on unrealistic data.
Method 2: Separate PGO Code
Alternatively, separate code entirely for PGO data collection, working on real data:
fn criterion_benchmark(c: &mut Criterion) {
// Excluded from PGO.
#[cfg(not(feature = "pgo"))]
{
bench_estimate(c);
bench_decompress(c);
bench_compress_file(c);
bench_create_dict(c);
}
// Only runs during PGO data collection.
#[cfg(feature = "pgo")]
{
generate_pgo_data();
}
}
This gives you more control over PGO data collection: use custom data, exclude unrealistic cases, or test multiple components together.
Integrate with Non-Template Projects
Info
If your project was not built on Reloaded template, here's how you can recreate the PGO parts.
Adding PGO support to existing Rust projects requires coordinated changes across build configuration and source code.
Environment Variable Setup
Add the PGO environment variable to your GitHub Actions workflow:
env:
build-with-pgo: true # Set to true to enable PGO builds
Build Matrix Configuration
Modify your build matrix to include the use-pgo parameter and call the GitHub action:
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
use-pgo: true
use-cross: false
- os: windows-latest
target: x86_64-pc-windows-msvc
use-pgo: true
use-cross: false
- name: Build C Libraries and Run Tests
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: ${{ github.event.repository.name }}
target: ${{ matrix.target }}
use-pgo: ${{ matrix.use-pgo && env.build-with-pgo }}
use-cross: ${{ matrix.use-cross }}
features: "c-exports"
build-library: true
Cross-Compilation Limitations
PGO is disabled for cross-compilation targets where native runners aren't available, as statistics collection would be impractical.
Adding PGO to Cargo.toml
Add the PGO feature to your Cargo.toml:
[features]
pgo = []
Adding Benchmarks
If you don't already have benchmarks, add them to your project. See the Configuring Benchmarks for PGO section for details on setting up benchmarks with PGO support.