From f4de59e234bfa7fb2a3a86764f390b09d4249a9b Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 17 Oct 2014 21:28:47 +0400 Subject: [PATCH] runtime/pprof: fix memory profiler test Don't use cmd/pprof as it is not necessary installed and does not work on nacl and plan9. Instead just look at the raw profile. LGTM=crawshaw, rsc R=golang-codereviews, crawshaw, 0intro, rsc CC=golang-codereviews https://golang.org/cl/159010043 --- src/runtime/pprof/mprof_test.go | 90 ++++++++------------------------- 1 file changed, 21 insertions(+), 69 deletions(-) diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go index 76ac02f2b7..ebf53dd66b 100644 --- a/src/runtime/pprof/mprof_test.go +++ b/src/runtime/pprof/mprof_test.go @@ -5,12 +5,8 @@ package pprof_test import ( - "bufio" "bytes" "fmt" - "io/ioutil" - "os" - "os/exec" "regexp" "runtime" . "runtime/pprof" @@ -52,23 +48,13 @@ func allocatePersistent1K() { var memoryProfilerRun = 0 func TestMemoryProfiler(t *testing.T) { - t.Skip("broken test - see issue 8867") - // Create temp file for the profile. - f, err := ioutil.TempFile("", "memprof") - if err != nil { - t.Fatalf("failed to create temp file: %v", err) - } - defer func() { - f.Close() - os.Remove(f.Name()) - }() - // Disable sampling, otherwise it's difficult to assert anything. oldRate := runtime.MemProfileRate runtime.MemProfileRate = 1 defer func() { runtime.MemProfileRate = oldRate }() + // Allocate a meg to ensure that mcache.next_sample is updated to 1. for i := 0; i < 1024; i++ { memSink = make([]byte, 1024) @@ -81,67 +67,33 @@ func TestMemoryProfiler(t *testing.T) { memSink = nil runtime.GC() // materialize stats - if err := WriteHeapProfile(f); err != nil { + var buf bytes.Buffer + if err := Lookup("heap").WriteTo(&buf, 1); err != nil { t.Fatalf("failed to write heap profile: %v", err) } - f.Close() memoryProfilerRun++ - checkMemProfile(t, f.Name(), []string{"--alloc_space", "--show_bytes", "--lines"}, []string{ - fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient1M .*mprof_test.go:25`, 1<<20*memoryProfilerRun), - fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient2M .*mprof_test.go:34`, 2<<20*memoryProfilerRun), - fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), - }, []string{}) - - checkMemProfile(t, f.Name(), []string{"--inuse_space", "--show_bytes", "--lines"}, []string{ - fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), - }, []string{ - "allocateTransient1M", - "allocateTransient2M", - }) -} -func checkMemProfile(t *testing.T, file string, addArgs []string, what []string, whatnot []string) { - args := []string{"tool", "pprof", "--text"} - args = append(args, addArgs...) - args = append(args, os.Args[0], file) - out, err := exec.Command("go", args...).CombinedOutput() - if err != nil { - t.Fatalf("failed to execute pprof: %v\n%v\n", err, string(out)) + tests := []string{ + fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:43 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:66 +`, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun), + + fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocateTransient1M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:21 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:64 +`, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun), + + fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:30 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:65 +`, memoryProfilerRun, (2<<20)*memoryProfilerRun), } - matched := make(map[*regexp.Regexp]bool) - for _, s := range what { - matched[regexp.MustCompile(s)] = false - } - var not []*regexp.Regexp - for _, s := range whatnot { - not = append(not, regexp.MustCompile(s)) - } - - s := bufio.NewScanner(bytes.NewReader(out)) - for s.Scan() { - ln := s.Text() - for re := range matched { - if re.MatchString(ln) { - if matched[re] { - t.Errorf("entry '%s' is matched twice", re.String()) - } - matched[re] = true - } - } - for _, re := range not { - if re.MatchString(ln) { - t.Errorf("entry '%s' is matched, but must not", re.String()) - } + for _, test := range tests { + if !regexp.MustCompile(test).Match(buf.Bytes()) { + t.Fatalf("The entry did not match:\n%v\n\nProfile:\n%v\n", test, buf.String()) } } - for re, ok := range matched { - if !ok { - t.Errorf("entry '%s' is not matched", re.String()) - } - } - if t.Failed() { - t.Logf("profile:\n%v", string(out)) - } } -- 2.48.1