Course contentsShow
← Rust
Lesson 1793 of 1,91015. Performance and Architectural EngineeringFree lesson

Link-Time Optimization Tactics

Configure build systems to allow cross-module inlining and dead code elimination.

In this lesson, you will learn how to leverage Link-Time Optimization (LTO) to dissolve module boundaries and enable the compiler to perform global dead code elimination and cross-module inlining.

The Problem of Module Boundaries

By default, the Rust compiler operates on a "per-crate" basis. When you compile, the compiler treats each crate (or even each codegen unit within a crate) as an isolated island. If you define a generic function in lib_a and call it in bin_b, the compiler cannot see the implementation of that function while optimizing bin_b. This prevents it from inlining the function or pruning branches that are provably unreachable based on how the function is used in the binary.

Enabling Global Visibility

LTO changes this by delaying the optimization phase until the final linking stage. Instead of emitting machine code immediately, the compiler emits LLVM bitcode. When the linker runs, it collects this bitcode from all crates, creating a "global view" of the entire program.

To enable this, you must configure your Cargo.toml. While lto = true (or lto = "fat") provides the most aggressive optimizations, it can significantly increase build times. For large systems, lto = "thin" is the preferred balance, as it performs incremental optimization and imports small functions across modules without the massive overhead of "fat" LTO.

[profile.release]
lto = "thin"    # Recommended for performance/build time balance
# lto = "fat"   # Use only when absolute performance is the priority

Impacts on Performance

When LTO is active, the compiler can effectively "see through" your architectural layers. If you have a deep abstraction stack built with traits or generic components—designed according to the Data-Oriented principles we've previously discussed—LTO will inline these abstractions, turning high-level code into simple, flat machine instructions. It also performs Cross-Module Dead Code Elimination (DCE): if a function is marked as pub in a library but never actually invoked by the final linked binary, LTO will identify it as unreachable and strip it entirely from the final executable, reducing your binary size and cache pressure.

Key Takeaway: Enable thin LTO in your release profiles to allow the compiler to perform cross-crate inlining and aggressive dead code removal, effectively flattening your abstractions at no runtime cost.