pgo
Use when a C or C++ binary needs profile-guided optimization with GCC or Clang: instrumented or sampled profiles, merging, the two-stage build, or BOLT. Not for base flags: use gcc or clang.
SKILL.md.devin/skills/pgo/SKILL.md
GitHubProfile-guided optimization
Contract
| Field | Bound contract |
|---|---|
| Trigger | The user asks how to apply PGO, how -fprofile-generate and -fprofile-use fit together, how to collect a representative profile, or how BOLT differs from PGO. |
| Authority | Read-only. The skill emits the build sequence, collection commands, and a measurement plan to chat; the user runs them. Rollback is not needed. No remote mutation. |
| Side effect | Chat output. |
| Done | A two-stage build sequence for the user's compiler is reported with the profile format named, the workload checklist is applied, and the speedup claim rests on a before-and-after measurement command rather than a number. |
Inputs
- Compiler and version: required. GCC 16.2 or Clang 23.1.0 are current stable; each has its own profile format.
- A representative workload the instrumented binary can run: required.
- Build system: required for wiring; CMake shown below.
- Whether
perfwith branch sampling is available: required for SamplePGO and BOLT. - Baseline flags already in use: required; PGO layers on
-O2or-O3.
Procedure
- Decide whether PGO applies. Standard optimization comes first:
-O2or-O3, and-march=for the deployment CPU. PGO pays off on code where static heuristics guess wrong: branch-heavy paths, many hot and cold functions, call-heavy code where inlining decisions matter. Do not promise a percentage; the gain is measured in step 7. Done when: the user knows PGO is a candidate and what will decide it. - Run the GCC flow. Instrument:
gcc -O2 -fprofile-generate -fprofile-dir=./pgo-data prog.c -o prog. Run the workload;.gcdafiles land in./pgo-data/. Rebuild:gcc -O2 -fprofile-use -fprofile-dir=./pgo-data -fprofile-correction prog.c -o prog. Keep the same output name in both builds, because GCC derives the.gcdafile name from the object name and a renamed second build reports-Wmissing-profile.-fprofile-correctionreconciles counts from multi-threaded runs; include it. Done when: the three commands share one output name. - Run the Clang instrumented flow. Instrument:
clang -O2 -fprofile-instr-generate prog.c -o prog_instr. Run the workload; it writesdefault.profraw, or per-process files withLLVM_PROFILE_FILE="prog-%p.profraw". Merge:llvm-profdata merge -output=prog.profdata *.profraw. Rebuild:clang -O2 -fprofile-instr-use=prog.profdata prog.c -o prog_pgo. Weight workloads with-weighted-input=3,a.profraw -weighted-input=1,b.profraw; inspect withllvm-profdata show --all-functions prog.profdata; compare two profiles withllvm-profdata overlap a.profdata b.profdata. Done when: the merged.profdataexists and the rebuild command names it. - Add context-sensitive PGO when inlining decisions matter: take the stage-1
.profdata, buildclang -O2 -fprofile-use=stage1.profdata -fcs-profile-generate, run the workload, merge the new.profrawfiles intocs.profdata, and build the final binary with-fprofile-use=cs.profdata. Done when: the second-stage profile feeds the final build. - Use sampling when instrumentation overhead is unacceptable. Build with
-fno-omit-frame-pointer, recordperf record -b -e cycles:u ./prog < workload, convertperf script -F ip,brstack > perf.script, thenllvm-profgen --binary=./prog --perfscript=perf.script --output=prog.profdata, and rebuild with-fprofile-sample-use=prog.profdata. GCC's sampling counterpart is-fauto-profile=<file>with a profile converted fromperfdata. Done when: the sample profile feeds the rebuild. - Apply BOLT after PGO when instruction-cache layout is the remaining cost. Link with
-Wl,--emit-relocs. Collectperf record -e cycles:u -j any,u -o perf.data -- ./prog < workload, convertperf2bolt -p perf.data -o perf.fdata ./prog, or instrument withllvm-bolt prog -instrument -o prog.instrand run it (profile lands in/tmp/prof.fdata). Optimize:llvm-bolt prog -o prog.bolt -data=perf.fdata -reorder-blocks=ext-tsp -reorder-functions=cdsort -split-functions -split-all-cold -split-eh -dyno-stats. GCC 8 and later need-fno-reorder-blocks-and-partitionat compile time for BOLT. Done when: the BOLT binary exists. - Measure.
hyperfine --runs 5 "./prog_baseline < workload" "./prog_pgo < workload" --export-markdown results.md, orperf staton each binary. Report the measured ratio and the noise across runs; a PGO or BOLT build that does not beat the baseline on the deployment workload is discarded. Done when: the numbers come from the user's workload. - Wire CMake with two options,
PGO_INSTRUMENTadding-fprofile-instr-generateto compile and link options andPGO_USEadding-fprofile-instr-use=<path>to both, driven by two configure-build cycles into separate build directories. Done when: the two build directories and the profile path are named.
Failure and recovery
| Failure class | Behavior |
|---|---|
| Workload not representative | Apply the checklist: covers the hot paths, runs long enough to exercise them, weights production scenarios higher, excludes debug builds and one-off startup unless startup matters. A tiny synthetic benchmark trains the wrong layout. |
-Wmissing-profile from GCC |
The second build's object name differs from the first; use one output name. |
perf record -b unsupported |
The CPU or VM lacks branch sampling; use instrumented PGO instead of SamplePGO and BOLT. |
llvm-bolt not installed |
BOLT builds as an LLVM project (-DLLVM_ENABLE_PROJECTS=bolt); report it missing rather than substituting. |
| Profile format mismatch | -fprofile-instr-* and -fprofile-generate/-fprofile-use are different formats in Clang; do not mix them across stages. |
Output
A chat report with the ordered build, run, merge, and rebuild commands for the user's compiler, the optional CS-PGO, SamplePGO, and BOLT steps when they apply, the workload checklist verdict, and the measurement command whose result decides whether the build ships.