Go

What do the block and mutex profiles measure, how do you enable them, and how do they differ?

Question 373HardGo 1.22 to 1.25

Both are disabled by default because they add overhead.

  • Block profile: where goroutines waited on synchronization primitives — channel send/recv, select, sync.Mutex, sync.Cond, WaitGroup.Wait. Records total delay per stack. Enabled with runtime.SetBlockProfileRate(ns): sample on average one blocking event per ns nanoseconds blocked; 1 = record everything.
  • Mutex profile: contention on sync.Mutex/RWMutex, attributed to the stack of the goroutine that held the lock and delayed others (reported at Unlock). Enabled with runtime.SetMutexProfileFraction(n): report ~1/n contention events.
func main() {
    runtime.SetBlockProfileRate(10_000)  // ~ one sample per 10µs blocked
    runtime.SetMutexProfileFraction(100) // 1% of contention events
    startDebugServer()
    // ...
}
// go tool pprof http://127.0.0.1:6060/debug/pprof/mutex
// go tool pprof http://127.0.0.1:6060/debug/pprof/block

Key distinction: block answers "where are my goroutines waiting?" (the victims); mutex answers "which critical section is causing the waiting?" (the culprit). Gotcha: the block profile includes intentional waiting (a worker idling on <-jobs), so filter with -focus. Neither shows time blocked in syscalls/network I/O — for that use the execution trace. In benchmarks: go test -bench=. -blockprofile=b.out -mutexprofile=m.out.

More on Performance, Profiling & Testing

All 38 Performance, Profiling & Testing questions