summaryrefslogtreecommitdiff
path: root/vendor/github.com/pkg/profile/profile.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pkg/profile/profile.go')
-rw-r--r--vendor/github.com/pkg/profile/profile.go244
1 files changed, 244 insertions, 0 deletions
diff --git a/vendor/github.com/pkg/profile/profile.go b/vendor/github.com/pkg/profile/profile.go
new file mode 100644
index 000000000..c44913a4c
--- /dev/null
+++ b/vendor/github.com/pkg/profile/profile.go
@@ -0,0 +1,244 @@
+// Package profile provides a simple way to manage runtime/pprof
+// profiling of your Go application.
+package profile
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+ "os/signal"
+ "path/filepath"
+ "runtime"
+ "runtime/pprof"
+ "sync/atomic"
+)
+
+const (
+ cpuMode = iota
+ memMode
+ mutexMode
+ blockMode
+ traceMode
+)
+
+// Profile represents an active profiling session.
+type Profile struct {
+ // quiet suppresses informational messages during profiling.
+ quiet bool
+
+ // noShutdownHook controls whether the profiling package should
+ // hook SIGINT to write profiles cleanly.
+ noShutdownHook bool
+
+ // mode holds the type of profiling that will be made
+ mode int
+
+ // path holds the base path where various profiling files are written.
+ // If blank, the base path will be generated by ioutil.TempDir.
+ path string
+
+ // memProfileRate holds the rate for the memory profile.
+ memProfileRate int
+
+ // closer holds a cleanup function that run after each profile
+ closer func()
+
+ // stopped records if a call to profile.Stop has been made
+ stopped uint32
+}
+
+// NoShutdownHook controls whether the profiling package should
+// hook SIGINT to write profiles cleanly.
+// Programs with more sophisticated signal handling should set
+// this to true and ensure the Stop() function returned from Start()
+// is called during shutdown.
+func NoShutdownHook(p *Profile) { p.noShutdownHook = true }
+
+// Quiet suppresses informational messages during profiling.
+func Quiet(p *Profile) { p.quiet = true }
+
+// CPUProfile enables cpu profiling.
+// It disables any previous profiling settings.
+func CPUProfile(p *Profile) { p.mode = cpuMode }
+
+// DefaultMemProfileRate is the default memory profiling rate.
+// See also http://golang.org/pkg/runtime/#pkg-variables
+const DefaultMemProfileRate = 4096
+
+// MemProfile enables memory profiling.
+// It disables any previous profiling settings.
+func MemProfile(p *Profile) {
+ p.memProfileRate = DefaultMemProfileRate
+ p.mode = memMode
+}
+
+// MemProfileRate enables memory profiling at the preferred rate.
+// It disables any previous profiling settings.
+func MemProfileRate(rate int) func(*Profile) {
+ return func(p *Profile) {
+ p.memProfileRate = rate
+ p.mode = memMode
+ }
+}
+
+// MutexProfile enables mutex profiling.
+// It disables any previous profiling settings.
+//
+// Mutex profiling is a no-op before go1.8.
+func MutexProfile(p *Profile) { p.mode = mutexMode }
+
+// BlockProfile enables block (contention) profiling.
+// It disables any previous profiling settings.
+func BlockProfile(p *Profile) { p.mode = blockMode }
+
+// Trace profile controls if execution tracing will be enabled. It disables any previous profiling settings.
+func TraceProfile(p *Profile) { p.mode = traceMode }
+
+// ProfilePath controls the base path where various profiling
+// files are written. If blank, the base path will be generated
+// by ioutil.TempDir.
+func ProfilePath(path string) func(*Profile) {
+ return func(p *Profile) {
+ p.path = path
+ }
+}
+
+// Stop stops the profile and flushes any unwritten data.
+func (p *Profile) Stop() {
+ if !atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
+ // someone has already called close
+ return
+ }
+ p.closer()
+ atomic.StoreUint32(&started, 0)
+}
+
+// started is non zero if a profile is running.
+var started uint32
+
+// Start starts a new profiling session.
+// The caller should call the Stop method on the value returned
+// to cleanly stop profiling.
+func Start(options ...func(*Profile)) interface {
+ Stop()
+} {
+ if !atomic.CompareAndSwapUint32(&started, 0, 1) {
+ log.Fatal("profile: Start() already called")
+ }
+
+ var prof Profile
+ for _, option := range options {
+ option(&prof)
+ }
+
+ path, err := func() (string, error) {
+ if p := prof.path; p != "" {
+ return p, os.MkdirAll(p, 0777)
+ }
+ return ioutil.TempDir("", "profile")
+ }()
+
+ if err != nil {
+ log.Fatalf("profile: could not create initial output directory: %v", err)
+ }
+
+ logf := func(format string, args ...interface{}) {
+ if !prof.quiet {
+ log.Printf(format, args...)
+ }
+ }
+
+ switch prof.mode {
+ case cpuMode:
+ fn := filepath.Join(path, "cpu.pprof")
+ f, err := os.Create(fn)
+ if err != nil {
+ log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
+ }
+ logf("profile: cpu profiling enabled, %s", fn)
+ pprof.StartCPUProfile(f)
+ prof.closer = func() {
+ pprof.StopCPUProfile()
+ f.Close()
+ logf("profile: cpu profiling disabled, %s", fn)
+ }
+
+ case memMode:
+ fn := filepath.Join(path, "mem.pprof")
+ f, err := os.Create(fn)
+ if err != nil {
+ log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
+ }
+ old := runtime.MemProfileRate
+ runtime.MemProfileRate = prof.memProfileRate
+ logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
+ prof.closer = func() {
+ pprof.Lookup("heap").WriteTo(f, 0)
+ f.Close()
+ runtime.MemProfileRate = old
+ logf("profile: memory profiling disabled, %s", fn)
+ }
+
+ case mutexMode:
+ fn := filepath.Join(path, "mutex.pprof")
+ f, err := os.Create(fn)
+ if err != nil {
+ log.Fatalf("profile: could not create mutex profile %q: %v", fn, err)
+ }
+ enableMutexProfile()
+ logf("profile: mutex profiling enabled, %s", fn)
+ prof.closer = func() {
+ if mp := pprof.Lookup("mutex"); mp != nil {
+ mp.WriteTo(f, 0)
+ }
+ f.Close()
+ disableMutexProfile()
+ logf("profile: mutex profiling disabled, %s", fn)
+ }
+
+ case blockMode:
+ fn := filepath.Join(path, "block.pprof")
+ f, err := os.Create(fn)
+ if err != nil {
+ log.Fatalf("profile: could not create block profile %q: %v", fn, err)
+ }
+ runtime.SetBlockProfileRate(1)
+ logf("profile: block profiling enabled, %s", fn)
+ prof.closer = func() {
+ pprof.Lookup("block").WriteTo(f, 0)
+ f.Close()
+ runtime.SetBlockProfileRate(0)
+ logf("profile: block profiling disabled, %s", fn)
+ }
+
+ case traceMode:
+ fn := filepath.Join(path, "trace.out")
+ f, err := os.Create(fn)
+ if err != nil {
+ log.Fatalf("profile: could not create trace output file %q: %v", fn, err)
+ }
+ if err := startTrace(f); err != nil {
+ log.Fatalf("profile: could not start trace: %v", err)
+ }
+ logf("profile: trace enabled, %s", fn)
+ prof.closer = func() {
+ stopTrace()
+ logf("profile: trace disabled, %s", fn)
+ }
+ }
+
+ if !prof.noShutdownHook {
+ go func() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+ <-c
+
+ log.Println("profile: caught interrupt, stopping profiles")
+ prof.Stop()
+
+ os.Exit(0)
+ }()
+ }
+
+ return &prof
+}