1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:18:32 -06:00

runtime/pprof: speed up CPU profiling shutdown

The core CPU profiling loop contains a 100ms sleep.
This is important to reduce overhead.

However, it means that it takes 200ms to shutting down a program
with CPU profiling enabled. When trying to collect many samples
by running a short-lived program many times, this adds up.

This change cuts the shutdown penalty in half by skipping
the sleep whenever possible.

Change-Id: Ic3177f8e1a2d331fe1a1ecd7c8c06f50beb42535
Reviewed-on: https://go-review.googlesource.com/c/go/+/228886
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
Josh Bleecher Snyder 2019-12-31 21:24:20 -08:00
parent 12d1c9b863
commit 1f0738c157

View File

@ -81,6 +81,7 @@ import (
"sort"
"strings"
"sync"
"sync/atomic"
"text/tabwriter"
"time"
"unsafe"
@ -714,10 +715,22 @@ func (p runtimeProfile) Stack(i int) []uintptr { return p[i].Stack() }
var cpu struct {
sync.Mutex
profiling bool
profiling uint32 // bool, accessed atomically
done chan bool
}
func cpuProfiling() bool {
return atomic.LoadUint32(&cpu.profiling) != 0
}
func setCPUProfiling(b bool) {
if b {
atomic.StoreUint32(&cpu.profiling, 1)
} else {
atomic.StoreUint32(&cpu.profiling, 0)
}
}
// StartCPUProfile enables CPU profiling for the current process.
// While profiling, the profile will be buffered and written to w.
// StartCPUProfile returns an error if profiling is already enabled.
@ -747,10 +760,10 @@ func StartCPUProfile(w io.Writer) error {
cpu.done = make(chan bool)
}
// Double-check.
if cpu.profiling {
if cpuProfiling() {
return fmt.Errorf("cpu profiling already in use")
}
cpu.profiling = true
setCPUProfiling(true)
runtime.SetCPUProfileRate(hz)
go profileWriter(w)
return nil
@ -767,7 +780,9 @@ func profileWriter(w io.Writer) {
b := newProfileBuilder(w)
var err error
for {
time.Sleep(100 * time.Millisecond)
if cpuProfiling() {
time.Sleep(100 * time.Millisecond)
}
data, tags, eof := readProfile()
if e := b.addCPUData(data, tags); e != nil && err == nil {
err = e
@ -792,10 +807,10 @@ func StopCPUProfile() {
cpu.Lock()
defer cpu.Unlock()
if !cpu.profiling {
if !cpuProfiling() {
return
}
cpu.profiling = false
setCPUProfiling(false)
runtime.SetCPUProfileRate(0)
<-cpu.done
}