]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/pprof: emit count profiles with debug=0 as proto profiles
authorMichael Matloob <matloob@golang.org>
Fri, 11 Nov 2016 20:01:58 +0000 (15:01 -0500)
committerMichael Matloob <matloob@golang.org>
Mon, 21 Nov 2016 17:15:30 +0000 (17:15 +0000)
count profiles with debug=1 retain their previous format.
Also add a test check for the proto profiles since all runtime/pprof
tests only look at the debug=1 profiles.

Change-Id: Ibe805585b597e5d3570807115940a1dc4535c03f
Reviewed-on: https://go-review.googlesource.com/33148
Run-TryBot: Michael Matloob <matloob@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/go/build/deps_test.go
src/runtime/pprof/pprof.go
src/runtime/pprof/pprof_test.go

index 4036e3b705ff0aa67bee88e226380b060d8cd077..e6f228852b98e8827d525b9963a82cb80e440630 100644 (file)
@@ -175,7 +175,7 @@ var pkgDeps = map[string][]string{
        "regexp/syntax":                     {"L2"},
        "runtime/debug":                     {"L2", "fmt", "io/ioutil", "os", "time"},
        "runtime/pprof/internal/protopprof": {"L2", "fmt", "internal/pprof/profile", "os", "time"},
-       "runtime/pprof":                     {"L2", "fmt", "os", "runtime/pprof/internal/protopprof", "text/tabwriter", "time"},
+       "runtime/pprof":                     {"L2", "fmt", "internal/pprof/profile", "os", "runtime/pprof/internal/protopprof", "text/tabwriter", "time"},
        "runtime/trace":                     {"L0"},
        "text/tabwriter":                    {"L2"},
 
index 70544acde19e10cb37ca8bc4fdf02b2e0b1cf304..8efa19434b32fd45306999e066f8f1386a891d40 100644 (file)
@@ -73,6 +73,7 @@ import (
        "bufio"
        "bytes"
        "fmt"
+       "internal/pprof/profile"
        "io"
        "runtime"
        "runtime/pprof/internal/protopprof"
@@ -340,17 +341,8 @@ type countProfile interface {
 }
 
 // printCountProfile prints a countProfile at the specified debug level.
+// The profile will be in compressed proto format unless debug is nonzero.
 func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
-       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, "%s profile: total %d\n", name, p.Len())
-
        // Build count of each stack.
        var buf bytes.Buffer
        key := func(stk []uintptr) string {
@@ -376,17 +368,37 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
 
        sort.Sort(&keysByCount{keys, count})
 
-       for _, k := range keys {
-               fmt.Fprintf(w, "%d %s\n", count[k], k)
-               if debug > 0 {
-                       printStackRecord(w, p.Stack(index[k]), false)
+       if debug > 0 {
+               // Print debug profile in legacy format
+               tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+               fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len())
+               for _, k := range keys {
+                       fmt.Fprintf(tw, "%d %s\n", count[k], k)
+                       printStackRecord(tw, p.Stack(index[k]), false)
                }
+               return tw.Flush()
        }
 
-       if tw != nil {
-               tw.Flush()
+       // Output profile in protobuf form.
+       prof := &profile.Profile{
+               PeriodType: &profile.ValueType{Type: name, Unit: "count"},
+               Period:     1,
+               Sample:     make([]*profile.Sample, 0, len(keys)),
+               SampleType: []*profile.ValueType{{Type: name, Unit: "count"}},
        }
-       return b.Flush()
+       for _, k := range keys {
+               stk := p.Stack(index[k])
+               c := count[k]
+               locs := make([]*profile.Location, len(stk))
+               for i, addr := range stk {
+                       locs[i] = &profile.Location{Address: uint64(addr) - 1}
+               }
+               prof.Sample = append(prof.Sample, &profile.Sample{
+                       Location: locs,
+                       Value:    []int64{int64(c)},
+               })
+       }
+       return prof.Write(w)
 }
 
 // keysByCount sorts keys with higher counts first, breaking ties by key string order.
index 47c29d0688ce512847f639daaed1ab04bdfdf9f4..fd0660780584807909ddedd9e21cad8c0b9aa0f0 100644 (file)
@@ -679,13 +679,31 @@ func TestGoroutineCounts(t *testing.T) {
        time.Sleep(10 * time.Millisecond) // let goroutines block on channel
 
        var w bytes.Buffer
-       Lookup("goroutine").WriteTo(&w, 1)
+       goroutineProf := Lookup("goroutine")
+
+       // Check debug profile
+       goroutineProf.WriteTo(&w, 1)
        prof := w.String()
 
        if !containsInOrder(prof, "\n50 @ ", "\n40 @", "\n10 @", "\n1 @") {
                t.Errorf("expected sorted goroutine counts:\n%s", prof)
        }
 
+       // Check proto profile
+       w.Reset()
+       goroutineProf.WriteTo(&w, 0)
+       p, err := profile.Parse(&w)
+       if err != nil {
+               t.Errorf("error parsing protobuf profile: %v", err)
+       }
+       if err := p.CheckValid(); err != nil {
+               t.Errorf("protobuf profile is invalid: %v", err)
+       }
+       if !containsCounts(p, []int64{50, 40, 10, 1}) {
+               t.Errorf("expected count profile to contain goroutines with counts %v, got %v",
+                       []int64{50, 40, 10, 1}, p)
+       }
+
        close(c)
 
        time.Sleep(10 * time.Millisecond) // let goroutines exit
@@ -701,3 +719,23 @@ func containsInOrder(s string, all ...string) bool {
        }
        return true
 }
+
+func containsCounts(prof *profile.Profile, counts []int64) bool {
+       m := make(map[int64]int)
+       for _, c := range counts {
+               m[c]++
+       }
+       for _, s := range prof.Sample {
+               // The count is the single value in the sample
+               if len(s.Value) != 1 {
+                       return false
+               }
+               m[s.Value[0]]--
+       }
+       for _, n := range m {
+               if n > 0 {
+                       return false
+               }
+       }
+       return true
+}