Index: src/pkg/runtime/pprof/pprof.go |
=================================================================== |
--- a/src/pkg/runtime/pprof/pprof.go |
+++ b/src/pkg/runtime/pprof/pprof.go |
@@ -36,6 +36,7 @@ |
// goroutine - stack traces of all current goroutines |
// heap - a sampling of all heap allocations |
// threadcreate - stack traces that led to the creation of new OS threads |
+// block - stack traces that led to blocking on synchronization primitives |
// |
// These predefine profiles maintain themselves and panic on an explicit |
// Add or Remove method call. |
@@ -76,6 +77,12 @@ |
write: writeHeap, |
} |
+var blockProfile = &Profile{ |
+ name: "block", |
+ count: countBlock, |
+ write: writeBlock, |
+} |
+ |
func lockProfiles() { |
profiles.mu.Lock() |
if profiles.m == nil { |
@@ -84,6 +91,7 @@ |
"goroutine": goroutineProfile, |
"threadcreate": threadcreateProfile, |
"heap": heapProfile, |
+ "block": blockProfile, |
} |
} |
} |
@@ -600,3 +608,60 @@ |
runtime.SetCPUProfileRate(0) |
<-cpu.done |
} |
+ |
+type byCycles []runtime.BlockProfileRecord |
+ |
+func (x byCycles) Len() int { return len(x) } |
+func (x byCycles) Swap(i, j int) { x[i], x[j] = x[j], x[i] } |
+func (x byCycles) Less(i, j int) bool { return x[i].Cycles > x[j].Cycles } |
+ |
+// countBlock returns the number of records in the blocking profile. |
+func countBlock() int { |
+ n, _ := runtime.BlockProfile(nil) |
+ return n |
+} |
+ |
+// writeBlock writes the current blocking profile to w. |
+func writeBlock(w io.Writer, debug int) error { |
+ var p []runtime.BlockProfileRecord |
+ n, ok := runtime.BlockProfile(nil) |
+ for { |
+ p = make([]runtime.BlockProfileRecord, n+50) |
+ n, ok = runtime.BlockProfile(p) |
+ if ok { |
+ p = p[:n] |
+ break |
+ } |
+ } |
+ |
+ sort.Sort(byCycles(p)) |
+ |
+ b := bufio.NewWriter(w) |
+ var tw *tabwriter.Writer |
+ w = b |
+ if debug > 0 { |
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) |
+ w = tw |
+ } |
+ |
+ fmt.Fprintf(w, "--- contention:\n") |
+ fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) |
+ for i := range p { |
+ r := &p[i] |
+ fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count) |
+ for _, pc := range r.Stack() { |
+ fmt.Fprintf(w, " %#x", pc) |
+ } |
+ fmt.Fprint(w, "\n") |
+ if debug > 0 { |
+ printStackRecord(w, r.Stack(), false) |
+ } |
+ } |
+ |
+ if tw != nil { |
+ tw.Flush() |
+ } |
+ return b.Flush() |
+} |
+ |
+func runtime_cyclesPerSecond() int64 |