Home | History | Annotate | Download | only in pprof
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package pprof_test
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"reflect"
     11 	"regexp"
     12 	"runtime"
     13 	. "runtime/pprof"
     14 	"testing"
     15 	"unsafe"
     16 )
     17 
     18 var memSink interface{}
     19 
     20 func allocateTransient1M() {
     21 	for i := 0; i < 1024; i++ {
     22 		memSink = &struct{ x [1024]byte }{}
     23 	}
     24 }
     25 
     26 //go:noinline
     27 func allocateTransient2M() {
     28 	memSink = make([]byte, 2<<20)
     29 }
     30 
     31 type Obj32 struct {
     32 	link *Obj32
     33 	pad  [32 - unsafe.Sizeof(uintptr(0))]byte
     34 }
     35 
     36 var persistentMemSink *Obj32
     37 
     38 func allocatePersistent1K() {
     39 	for i := 0; i < 32; i++ {
     40 		// Can't use slice because that will introduce implicit allocations.
     41 		obj := &Obj32{link: persistentMemSink}
     42 		persistentMemSink = obj
     43 	}
     44 }
     45 
     46 // Allocate transient memory using reflect.Call.
     47 
     48 func allocateReflectTransient() {
     49 	memSink = make([]byte, 2<<20)
     50 }
     51 
     52 func allocateReflect() {
     53 	rv := reflect.ValueOf(allocateReflectTransient)
     54 	rv.Call(nil)
     55 }
     56 
     57 var memoryProfilerRun = 0
     58 
     59 func TestMemoryProfiler(t *testing.T) {
     60 	// Disable sampling, otherwise it's difficult to assert anything.
     61 	oldRate := runtime.MemProfileRate
     62 	runtime.MemProfileRate = 1
     63 	defer func() {
     64 		runtime.MemProfileRate = oldRate
     65 	}()
     66 
     67 	// Allocate a meg to ensure that mcache.next_sample is updated to 1.
     68 	for i := 0; i < 1024; i++ {
     69 		memSink = make([]byte, 1024)
     70 	}
     71 
     72 	// Do the interesting allocations.
     73 	allocateTransient1M()
     74 	allocateTransient2M()
     75 	allocatePersistent1K()
     76 	allocateReflect()
     77 	memSink = nil
     78 
     79 	runtime.GC() // materialize stats
     80 	var buf bytes.Buffer
     81 	if err := Lookup("heap").WriteTo(&buf, 1); err != nil {
     82 		t.Fatalf("failed to write heap profile: %v", err)
     83 	}
     84 
     85 	memoryProfilerRun++
     86 
     87 	tests := []string{
     88 		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]+
     89 #	0x[0-9,a-f]+	runtime/pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:41
     90 #	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test\.go:75
     91 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
     92 
     93 		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]+
     94 #	0x[0-9,a-f]+	runtime/pprof_test\.allocateTransient1M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:22
     95 #	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:73
     96 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
     97 
     98 		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]+
     99 #	0x[0-9,a-f]+	runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:28
    100 #	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:74
    101 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
    102 
    103 		fmt.Sprintf(`0: 0 \[%v: %v\] @( 0x[0-9,a-f]+)+
    104 #	0x[0-9,a-f]+	runtime/pprof_test\.allocateReflectTransient\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:49
    105 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
    106 	}
    107 
    108 	for _, test := range tests {
    109 		if !regexp.MustCompile(test).Match(buf.Bytes()) {
    110 			t.Fatalf("The entry did not match:\n%v\n\nProfile:\n%v\n", test, buf.String())
    111 		}
    112 	}
    113 }
    114