Skip to content

pprof Profiling

In Node.js you have node --prof (V8 CPU profiler), node --inspect (Chrome DevTools), and tools like clinic.js (clinic doctor, clinic flame) for heap and event-loop analysis. All are out-of-process or require wrapping your start command.

Go ships with runtime/pprof in the standard library and net/http/pprof for live HTTP-based profiling — no external tools needed for collection, and the go tool pprof command handles analysis.

Playground note: pprof requires writing profile files to disk and running go tool pprof. The code blocks below are real files — run them locally.

main.go
package main
import (
"os"
"runtime/pprof"
"log"
)
func main() {
// --- CPU profile ---
cpuFile, err := os.Create("cpu.out")
if err != nil {
log.Fatal(err)
}
defer cpuFile.Close()
if err := pprof.StartCPUProfile(cpuFile); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
// ... your code under test ...
doWork()
// --- Heap profile (write at the end) ---
heapFile, err := os.Create("mem.out")
if err != nil {
log.Fatal(err)
}
defer heapFile.Close()
pprof.WriteHeapProfile(heapFile)
}

2. HTTP endpoint (for long-running servers)

Section titled “2. HTTP endpoint (for long-running servers)”
main.go
package main
import (
"net/http"
_ "net/http/pprof" // blank import registers /debug/pprof/ routes
"log"
)
func main() {
// Your application server
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
// ... rest of app ...
}

Available endpoints:

  • http://localhost:6060/debug/pprof/ — index
  • http://localhost:6060/debug/pprof/profile?seconds=30 — 30-second CPU profile
  • http://localhost:6060/debug/pprof/heap — heap snapshot
  • http://localhost:6060/debug/pprof/goroutine — all goroutine stacks
  • http://localhost:6060/debug/pprof/trace?seconds=5 — execution trace
TypeScript
// Node.js — several tools, all external
// Option 1: built-in V8 profiler
node --prof server.js
node --prof-process isolate-*.log > report.txt
// Option 2: clinic.js (npm install -g clinic)
clinic doctor -- node server.js
clinic flame -- node server.js
// Option 3: Chrome DevTools
node --inspect server.js // open chrome://inspect
Go
// Go — single tool, ships with the toolchain
// Collect a 30-second CPU profile from a live server:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
// Collect from a file written by runtime/pprof:
go tool pprof cpu.out
// Open an interactive web UI (needs Graphviz):
go tool pprof -http=:8080 cpu.out
Terminal window
# Start interactive pprof shell
go tool pprof cpu.out
# Inside the shell:
(pprof) top10 # top 10 functions by CPU time
(pprof) list myFunc # annotated source for myFunc
(pprof) web # open SVG flame graph in browser
(pprof) pdf # save as PDF
# Or open the web UI directly (nicer flame graphs)
go tool pprof -http=:8080 cpu.out

Example top10 output:

Showing nodes accounting for 2.40s, 96.77% of 2.48s total
flat flat% sum% cum cum%
1.20s 48.39% 48.39% 1.20s 48.39% runtime.mallocgc
0.60s 24.19% 72.58% 0.60s 24.19% strings.(*Builder).WriteString
0.30s 12.10% 84.68% 0.30s 12.10% main.processItem
ColumnMeaning
flatTime spent in this function (excluding callees)
flat%Percentage of total profile time
cumCumulative time (this function + all functions it called)
cum%Cumulative percentage
Terminal window
go tool pprof mem.out
(pprof) top10 -cum # top allocators by cumulative bytes
(pprof) list myFunc # line-level allocation counts

A heap profile shows:

  • alloc_objects / alloc_space — total allocations since program start
  • inuse_objects / inuse_space — objects/bytes currently in use (after GC)
Terminal window
# Write CPU + memory profiles during a benchmark run
go test -bench=BenchmarkFoo -cpuprofile=cpu.out -memprofile=mem.out ./...
# Then analyse
go tool pprof cpu.out
go tool pprof mem.out
Terminal window
# Check for goroutine leaks (should stay flat over time)
go tool pprof http://localhost:6060/debug/pprof/goroutine
# Execution trace — shows scheduling, GC, goroutine lifecycle
curl -s "http://localhost:6060/debug/pprof/trace?seconds=5" > trace.out
go tool trace trace.out

The execution trace is the most detailed view: it shows every goroutine start/stop, GC pause, network block, and system call — similar to what clinic doctor does for Node’s event loop.

What blank import registers the /debug/pprof/ HTTP endpoints?
In pprof output, what does the "flat" column represent?
Which command opens an interactive flame graph web UI for a profile file?
Why should you never expose pprof endpoints on a public interface?