advancedWhole Program
What is the difference between LTO and PGO, and can you use both?
Whether the candidate can separate two orthogonal things people habitually confuse — seeing more code versus knowing more about execution — and whether they know what a bad profile costs.
What a strong answer covers
- They are orthogonal. Link-time optimization is about *scope*: instead of optimizing each translation unit in isolation and letting the linker concatenate the results, the compiler defers code generation, hands IR to the link step and optimizes across module boundaries. That enables cross-module inlining, whole-program devirtualization, better alias information and dead-code elimination of anything genuinely unreachable. It costs link time and memory, sometimes dramatically, and it makes builds less parallel — which is why thin variants exist that keep a per-module summary and parallelize.
- Profile-guided optimization is about *information*: you build an instrumented binary or sample a production one, run a representative workload, and feed the resulting counts back in. The compiler then knows which branches are taken, which functions are hot, which call sites are monomorphic in practice. It uses that for block layout so the hot path is straight-line and cache-friendly, for inlining decisions, for choosing which functions to optimize for size, and for hot/cold splitting.
- They compose, and they compose well: PGO tells the inliner what is worth inlining, LTO gives it more candidates to inline. Most large-scale deployments run both.
- The failure mode of PGO is the one worth being able to state: an unrepresentative profile makes it worse. Profile from a benchmark that exercises a code path nobody uses in production and you get hot layout for cold code, cold layout for the hot path, and a regression that no local measurement reproduces. Profiles also go stale as the code changes, so the pipeline needs a story for regenerating them, and it is that operational cost — not the compiler flag — that decides whether a team can use PGO at all.
✓ Green flags
- States the axis for each: scope versus information.
- Names concrete PGO uses beyond inlining — block layout, hot/cold splitting, size versus speed per function.
- Knows LTO costs link time and parallelism, and that thin variants exist because of it.
- Raises unrepresentative and stale profiles as the real risk.
- Treats profile collection as a pipeline problem rather than a flag.
✗ Red flags
- "They are basically the same, both are advanced optimizations." They answer different questions and can be enabled independently.
- "PGO always helps, it is just more information." An unrepresentative profile is worse than no profile, because the compiler acts on it confidently.
- "LTO is just -O3 across files." -O3 is a pass selection; LTO is a change in what the optimizer can see.
- "You can collect the profile from your test suite." Test suites exercise error paths and edge cases in proportions nothing like production.
Follow-up
You enable LTO and the build takes 40 minutes. What are your options, and what does each give up?
Implementation challenge
What to ask them to write or trace on a whiteboard.
Describe the build pipeline for a service that uses both: what artifacts exist at each stage, and where the profile enters.