aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/pprof/pprof_test.go
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2016-11-10 13:31:41 -0500
committerMichael Matloob <matloob@golang.org>2016-11-10 21:07:48 +0000
commit76f12cdaa2be0b96d314762ff5b2e403d1359cd8 (patch)
tree951799799bb57d41a3f767200f37088dfbeabe88 /src/runtime/pprof/pprof_test.go
parent7448eb4172bfc8f704b9ea39d77d0113a042b9dc (diff)
downloadgo-76f12cdaa2be0b96d314762ff5b2e403d1359cd8.tar.xz
runtime/pprof: output CPU profiles in pprof protobuf format
This change buffers the entire profile and converts in one shot in the profile writer, and could use more memory than necessary to output protocol buffer formatted profiles. It should be possible to convert each chunk in a stream (maybe maintaining some minimal state to output in the end) which could save on memory usage. Fixes #16093 Change-Id: I946c6a2b044ae644c72c8bb2d3bd82c415b1a847 Reviewed-on: https://go-review.googlesource.com/33071 Run-TryBot: Michael Matloob <matloob@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime/pprof/pprof_test.go')
-rw-r--r--src/runtime/pprof/pprof_test.go63
1 files changed, 30 insertions, 33 deletions
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index a683a03211..c19ea3507d 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -9,6 +9,7 @@ package pprof_test
import (
"bytes"
"fmt"
+ "internal/pprof/profile"
"internal/testenv"
"math/big"
"os"
@@ -20,7 +21,6 @@ import (
"sync"
"testing"
"time"
- "unsafe"
)
func cpuHogger(f func(), dur time.Duration) {
@@ -87,40 +87,17 @@ func TestCPUProfileMultithreaded(t *testing.T) {
}
func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) {
- // Convert []byte to []uintptr.
- l := len(valBytes)
- if i := bytes.Index(valBytes, []byte("\nMAPPED_LIBRARIES:\n")); i >= 0 {
- l = i
+ p, err := profile.Parse(bytes.NewReader(valBytes))
+ if err != nil {
+ t.Fatal(err)
}
- l /= int(unsafe.Sizeof(uintptr(0)))
- val := *(*[]uintptr)(unsafe.Pointer(&valBytes))
- val = val[:l]
-
- // 5 for the header, 3 for the trailer.
- if l < 5+3 {
- t.Logf("profile too short: %#x", val)
- if badOS[runtime.GOOS] {
- t.Skipf("ignoring failure on %s; see golang.org/issue/13841", runtime.GOOS)
- return
+ for _, sample := range p.Sample {
+ count := uintptr(sample.Value[0])
+ stk := make([]uintptr, len(sample.Location))
+ for i := range sample.Location {
+ stk[i] = uintptr(sample.Location[i].Address)
}
- t.FailNow()
- }
-
- hd, val, tl := val[:5], val[5:l-3], val[l-3:]
- if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
- t.Fatalf("unexpected header %#x", hd)
- }
-
- if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
- t.Fatalf("malformed end-of-data marker %#x", tl)
- }
-
- for len(val) > 0 {
- if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
- t.Fatalf("malformed profile. leftover: %#x", val)
- }
- f(val[0], val[2:2+val[1]])
- val = val[2+val[1]:]
+ f(count, stk)
}
}
@@ -674,3 +651,23 @@ func containsInOrder(s string, all ...string) bool {
}
return true
}
+
+// Tests that the profiler outputs a parsable protobuf Profile profile.
+func TestCPUProfileParse(t *testing.T) {
+
+ var before, after runtime.MemStats
+ runtime.ReadMemStats(&before)
+ var buf bytes.Buffer
+
+ if err := StartCPUProfile(&buf); err != nil {
+ t.Fatalf("Profile failed: Could not enable CPU profiling: %s\n", err)
+ }
+ time.Sleep(5 * time.Second)
+ StopCPUProfile()
+
+ runtime.ReadMemStats(&after)
+ _, err := profile.Parse(&buf)
+ if err != nil {
+ t.Fatalf("Could not parse Profile profile: %v", err)
+ }
+}