Reduce Compilation Duration
Recipe | Crates | Categories |
---|---|---|
Use Dynamic Linking | ||
Compile Incrementally | ||
Measure Build Times | ||
Optimize Compilation Levels | ||
Measure Build Times |
Rust compile times can be long. Reducing Rust compilation duration involves several strategies, targeting both the compiler and project structure. Here's a breakdown:
Project Structure and Dependencies
- Reduce the number of dependencies. Analyze your
Cargo.toml
and eliminate unused or redundant dependencies. Consider alternatives if a dependency is excessively large or slow to compile. - For multi-crate projects, use a workspace to share dependencies and enable workspace-level optimizations. This can reduce redundant compilation.
- Avoid Unnecessary Recompilation: Be mindful of changes that trigger recompilation. For example, changing build scripts or modifying
Cargo.toml
can invalidate the cache. - Use feature flags to conditionally compile code. This allows you to exclude unnecessary code during development, reducing compilation time.
- Precompiled Dependencies: For large, infrequently changing dependencies, consider using precompiled versions if available.
- Code Organization: Organizing your code into smaller, independent modules can improve incremental compilation by reducing the scope of changes.
Compiler-Level Optimizations
- Build Profiles: Use the
dev
profile for development, which prioritizes fast compilation over optimizations. Switch to therelease
profile only for final builds. - Ensure incremental compilation is enabled (the default). It reuses previously compiled code, significantly speeding up subsequent builds after changes. Avoid actions that invalidate the cache, such as changing dependencies or build scripts unnecessarily.
- Increasing the number of codegen units (
rustc
flag:-C codegen-units=N
) allows the compiler to parallelize code generation. Experiment to find the optimal value; too many can hinder Link-Time Optimization (LTO). - Tune Link-Time Optimization (LTO). While LTO can improve runtime performance, it increases compile time, especially "fat" LTO.
Consider using "thin" LTO (
-C lto=thin
) for a faster, though less aggressive, approach. For debug builds, disable LTO entirely (-C lto=no
). - Profile-Guided Optimization (PGO): PGO can improve runtime performance but requires additional compilation and profiling steps, thus increasing overall build time. Use PGO only for release builds where runtime performance is critical, and not for general development.
- Ccache: Using ccache can dramatically speed up compilation by caching compiled objects. It's particularly effective when recompiling similar code across multiple projects or branches.
Build Machine Hardware Considerations
- CPU Cores: A multi-core CPU significantly speeds up compilation, especially when using multiple codegen units.
- RAM: Sufficient RAM is essential, especially when using LTO or compiling large projects.
- SSD: A fast SSD can greatly reduce I/O bottlenecks during compilation.
Tools
cargo-bloat
⮳ can help you identify large dependencies contributing to compile times.cargo-graph
can visualize your dependency graph, making it easier to identify potential issues.
Profiling: cargo flamegraph, perf (system profiler) Code Optimization: (Often done without specific crates, focusing on algorithmic efficiency, data structures, and avoiding unnecessary allocations/copies) Dependency Management: (Minimize dependencies, use cargo tree to analyze) Link-Time Optimization (LTO): (Controlled via Cargo.toml) Incremental Compilation: (Leverage Cargo's caching, be mindful of changes that invalidate the cache) Build Profiles: (Optimize for release builds with appropriate flags in Cargo.toml) Compiler Flags: (Experiment with compiler flags, but be careful and measure improvements) Code Generation: (Avoid excessive monomorphization, consider techniques like dynamic dispatch where applicable)
Measure Build Times
time cargo build
cargo build --timings
Optimize Compilation Levels
In config.toml
# Enable a small amount of optimization in debug mode
[profile.dev]
opt-level = 1
# Enable high optimizations for dependencies, but not for our code:
[profile.dev.package."*"]
opt-level = 3
Use Dynamic Linking
cargo install cargo-add-dynamic
cargo add-dynamic polars --features csv-file,lazy,list,describe,rows,fmt,strings,temporal
cargo build
Speeding up incremental Rust compilation with dylibs⮳.
Compile Incrementally
From-scratch builds with incremental compilation enabled adds about 15–20% overhead compared to disabled. The initial build needs to write out more intermediate state in order for later incremental builds to take advantage of it. In a CI situation, it would be extremely unusual for there to be a later incremental build within the same job. The jobs are not making changes to source code and rebuilding. However, workflows that cache the target directory across runs might be benefiting from incremental compilation.
References
- Eight solutions for troubleshooting your Rust build times⮳.
- How I improved my Rust compile times by seventy-five percent⮳.
- Rust compilation time⮳.
Related Topics
- Benchmarking.
- Build Utils.
- Development Tools.
- Development Tools: Build Utils.
- Development Tools: Cargo Plugins.
- Development Tools: Profiling.
- Faster Linking.
- Performance.