What is Profile-Guided Optimization (PGO) in Go and how do you use it in production?
Question 438HardGo 1.22 to 1.25
PGO became generally available in Go 1.21. The compiler uses a CPU profile from representative production load to make better decisions: inlining hot call sites more aggressively, and devirtualizing hot interface or function-value calls into direct calls guarded by a type check. Typical gains are 2 to 14% CPU.
# 1. collect a CPU profile from prod (net/http/pprof)
curl -o cpu.pprof "http://svc:6060/debug/pprof/profile?seconds=30"
# 2. place it as default.pgo in the main package directory
mv cpu.pprof ./cmd/server/default.pgo
# 3. build: -pgo=auto is the default, picks up default.pgo
go build ./cmd/server
go build -pgo=off ./cmd/server # disable
go build -pgo=/path/merged.pprof ./... # explicit
go tool pprof -proto a.pprof b.pprof > merged.pprof # merge profiles
What interviewers look for:
- Commit
default.pgoso that builds stay reproducible. - PGO tolerates stale profiles. Samples are matched by function name and line offset within the function, so edits elsewhere in a file do not invalidate them, and refactors degrade the benefit gradually rather than breaking the build.
- Building with a profile from the PGO-optimized binary is fine and converges.
- Expect larger binaries and longer builds.
- Profile representative traffic, not a benchmark in a loop.
- The profile applies to the whole build, dependencies included.
Pairs well with: GOAMD64=v3, and checking inlining decisions with -gcflags=-m.
More on Modules, Packages & Tooling
- Q436Go forbids import cycles. How do you detect and break them?
- Q437A vulnerable dependency shows up in your build. How do you find out why it's there and upgrade it safely?
- Q439How does Go ship behavior changes without breaking old code? Explain GODEBUG, the godebug directive and //go:debug. What does this print?
- Q440What are module graph pruning and lazy module loading (Go 1.17), and why did go.mod files get so much longer?
- Q441Explain the build cache, the module cache and test result caching. When does go test print "(cached)" and how do you defeat it?
- Q442What is //go:linkname, and what changed about it in Go 1.23?