diff options
Diffstat (limited to 'src/runtime/pprof/pprof.go')
| -rw-r--r-- | src/runtime/pprof/pprof.go | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index b4f9ab8f7a..d3b7df3c1b 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -357,6 +357,7 @@ type stackProfile [][]uintptr func (x stackProfile) Len() int { return len(x) } func (x stackProfile) Stack(i int) []uintptr { return x[i] } +func (x stackProfile) Label(i int) *labelMap { return nil } // A countProfile is a set of stack traces to be printed as counts // grouped by stack trace. There are multiple implementations: @@ -365,6 +366,7 @@ func (x stackProfile) Stack(i int) []uintptr { return x[i] } type countProfile interface { Len() int Stack(i int) []uintptr + Label(i int) *labelMap } // printCountCycleProfile outputs block profile records (for block or mutex profiles) @@ -402,12 +404,16 @@ func printCountCycleProfile(w io.Writer, countName, cycleName string, scaler fun func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { // Build count of each stack. var buf bytes.Buffer - key := func(stk []uintptr) string { + key := func(stk []uintptr, lbls *labelMap) string { buf.Reset() fmt.Fprintf(&buf, "@") for _, pc := range stk { fmt.Fprintf(&buf, " %#x", pc) } + if lbls != nil { + buf.WriteString("\n# labels: ") + buf.WriteString(lbls.String()) + } return buf.String() } count := map[string]int{} @@ -415,7 +421,7 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro var keys []string n := p.Len() for i := 0; i < n; i++ { - k := key(p.Stack(i)) + k := key(p.Stack(i), p.Label(i)) if count[k] == 0 { index[k] = i keys = append(keys, k) @@ -449,7 +455,16 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro // For count profiles, all stack addresses are // return PCs, which is what appendLocsForStack expects. locs = b.appendLocsForStack(locs[:0], p.Stack(index[k])) - b.pbSample(values, locs, nil) + idx := index[k] + var labels func() + if p.Label(idx) != nil { + labels = func() { + for k, v := range *p.Label(idx) { + b.pbLabel(tagSample_Label, k, v, 0) + } + } + } + b.pbSample(values, locs, labels) } b.build() return nil @@ -645,7 +660,12 @@ func countThreadCreate() int { // writeThreadCreate writes the current runtime ThreadCreateProfile to w. func writeThreadCreate(w io.Writer, debug int) error { - return writeRuntimeProfile(w, debug, "threadcreate", runtime.ThreadCreateProfile) + // Until https://golang.org/issues/6104 is addressed, wrap + // ThreadCreateProfile because there's no point in tracking labels when we + // don't get any stack-traces. + return writeRuntimeProfile(w, debug, "threadcreate", func(p []runtime.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { + return runtime.ThreadCreateProfile(p) + }) } // countGoroutine returns the number of goroutines. @@ -653,12 +673,15 @@ func countGoroutine() int { return runtime.NumGoroutine() } +// runtime_goroutineProfileWithLabels is defined in runtime/mprof.go +func runtime_goroutineProfileWithLabels(p []runtime.StackRecord, labels []unsafe.Pointer) (n int, ok bool) + // writeGoroutine writes the current runtime GoroutineProfile to w. func writeGoroutine(w io.Writer, debug int) error { if debug >= 2 { return writeGoroutineStacks(w) } - return writeRuntimeProfile(w, debug, "goroutine", runtime.GoroutineProfile) + return writeRuntimeProfile(w, debug, "goroutine", runtime_goroutineProfileWithLabels) } func writeGoroutineStacks(w io.Writer) error { @@ -682,7 +705,7 @@ func writeGoroutineStacks(w io.Writer) error { return err } -func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord) (int, bool)) error { +func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord, []unsafe.Pointer) (int, bool)) error { // Find out how many records there are (fetch(nil)), // allocate that many records, and get the data. // There's a race—more records might be added between @@ -690,13 +713,15 @@ func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runti // and also try again if we're very unlucky. // The loop should only execute one iteration in the common case. var p []runtime.StackRecord - n, ok := fetch(nil) + var labels []unsafe.Pointer + n, ok := fetch(nil, nil) for { // Allocate room for a slightly bigger profile, // in case a few more entries have been added // since the call to ThreadProfile. p = make([]runtime.StackRecord, n+10) - n, ok = fetch(p) + labels = make([]unsafe.Pointer, n+10) + n, ok = fetch(p, labels) if ok { p = p[0:n] break @@ -704,13 +729,17 @@ func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runti // Profile grew; try again. } - return printCountProfile(w, debug, name, runtimeProfile(p)) + return printCountProfile(w, debug, name, &runtimeProfile{p, labels}) } -type runtimeProfile []runtime.StackRecord +type runtimeProfile struct { + stk []runtime.StackRecord + labels []unsafe.Pointer +} -func (p runtimeProfile) Len() int { return len(p) } -func (p runtimeProfile) Stack(i int) []uintptr { return p[i].Stack() } +func (p *runtimeProfile) Len() int { return len(p.stk) } +func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack() } +func (p *runtimeProfile) Label(i int) *labelMap { return (*labelMap)(p.labels[i]) } var cpu struct { sync.Mutex |
