profile-guided optimization
/ PGO /
An optimizer constantly makes guesses about your program: which branch of an if is usually taken, which functions are hot enough to inline, which loops run often. Without running the program, it can only guess from heuristics. Profile-guided optimization replaces those guesses with measurements: you run the program first to collect data about how it actually behaves, then recompile using that data to make better-informed decisions.
PGO is a three-step workflow. First, build an instrumented version of the program, one that records run-time facts: how often each branch goes which way, how many times each function is called, which paths are hot. Second, run that build on representative, realistic input — a workload that resembles production use — producing a profile (a data file of counts). Third, recompile from the same source, this time feeding the compiler the profile. Armed with real frequencies, the optimizer makes sharper choices: inline the functions that are genuinely hot, lay out the common branch as the fall-through (so the predicted path is cheaper), group hot code together for better instruction-cache behavior, and avoid bloating cold paths. A related sampling variant collects the profile from production with a low-overhead profiler instead of a special instrumented build.
It matters because the optimizer's static heuristics are often wrong about which code is hot, and PGO can deliver meaningful speedups (commonly a notable percentage on large applications) precisely by replacing guesses with truth — it is feedback-directed compilation. Honest caveats: PGO is only as good as the profiling workload. If your training input does not resemble real usage, you optimize for the wrong case and may even slow real workloads down. It complicates the build (compile, run, compile again) and the profile can go stale as the code changes. And it is an optimization for performance, not correctness — it never changes what the program computes, only how the compiler prioritizes its effort.
$ gcc -O2 -fprofile-generate prog.c -o prog # 1. build instrumented binary $ ./prog < representative_input # 2. run on realistic data -> writes a profile $ gcc -O2 -fprofile-use prog.c -o prog # 3. recompile, guided by the measured profile
Generate a profile from a realistic run, then recompile using it so the optimizer prioritizes the truly hot code.
PGO is only as good as its training workload: a profile from unrepresentative input optimizes for the wrong case and can slow real usage down; it changes performance, never correctness, and profiles go stale as code evolves.