Meet the Go Profiler
You just joined the platform team. The hello-api service is running fine on port
8080, and (because good Go services do this) it exposes the
pprof endpoints under /debug/pprof/. Nothing
is broken today. Your job is to get comfortable with the profiler anyway, so that
when something does break, reading a profile is muscle memory instead of a frantic
search through docs.
The app has three endpoints you can poke at:
GET /says helloGET /workburns CPU for a bit (great for generating load)GET /allocateretains 1 MiB per call (matters later, when we talk about heap profiles)
Task 1: Find the profiler
Every profile the Go runtime can produce is listed on the profiler's index page.
Fetch http://localhost:8080/debug/pprof/ and confirm the built-ins are all there:
profile (CPU), heap, goroutine, allocs, block, mutex, threadcreate,
and trace.
Hint 1
Plain old curl http://localhost:8080/debug/pprof/ does it.
Hint 2
The index is plain HTML. Look for href='profile?debug=1'-style links and note
they're relative paths under /debug/pprof/.
Task 2: Capture a CPU profile
The CPU profiler samples which function is running, over and over, until you stop.
Collect a 5-second profile and save the raw bytes to /tmp/cpu.prof:
curl -o /tmp/cpu.prof 'http://localhost:8080/debug/pprof/profile?seconds=5'
The command blocks for the whole 5 seconds. That's not a hang; it's the sampling window. What lands in the file is a gzip-compressed protobuf in the pprof format.
Hint 3
-o writes the response body exactly as received, which is what you want. Don't
pipe it through anything that might reformat it.
Task 3: Read the profile
A profile file is just compressed protobuf until go tool pprof reads it:
go tool pprof -top /tmp/cpu.prof
The -top report lists the hottest functions. Somewhere in there you should find
main.busyLoop, the function behind the /work endpoint... provided the profile
actually caught the app doing work. Find it to finish the challenge.
Hint 4
If the report says Total samples = 0, the app was idle while you profiled. CPU
profiling samples running code, not sleeping code, so an idle profile is an empty
profile. Generate load during the capture:
for i in $(seq 1 50); do curl -s -o /dev/null http://localhost:8080/work & done
curl -o /tmp/cpu.prof 'http://localhost:8080/debug/pprof/profile?seconds=5'
Hint 5
Expect main.busyLoop at the very top, holding nearly all the samples. The two
percentage columns: flat% is time in the function itself, cum% also counts
everything it calls.
Where to go next
- Capture
/debug/pprof/heapafter hammering/allocatea few times, then look formain.allocatein the report. - Get a plain-text goroutine dump:
curl 'http://localhost:8080/debug/pprof/goroutine?debug=1'. - When you're comfortable, take on the follow-up challenge, The Goroutine Leak (coming soon). Same service family, but this time something actually is broken.