github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/runtime/pprof/protomem_test.go (about) 1 // Copyright 2016 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 6 7 import ( 8 "bytes" 9 "internal/pprof/profile" 10 "io/ioutil" 11 "reflect" 12 "runtime" 13 "testing" 14 "time" 15 ) 16 17 // TestSampledHeapAllocProfile tests encoding of a memory profile from 18 // runtime.MemProfileRecord data. 19 func TestSampledHeapAllocProfile(t *testing.T) { 20 if runtime.GOOS != "linux" { 21 t.Skip("Test requires a system with /proc/self/maps") 22 } 23 24 // Figure out two addresses from /proc/self/maps. 25 mmap, err := ioutil.ReadFile("/proc/self/maps") 26 if err != nil { 27 t.Fatal("Cannot read /proc/self/maps") 28 } 29 rd := bytes.NewReader(mmap) 30 mprof := &profile.Profile{} 31 if err = mprof.ParseMemoryMap(rd); err != nil { 32 t.Fatalf("Cannot parse /proc/self/maps") 33 } 34 if len(mprof.Mapping) < 2 { 35 // It is possible for a binary to only have 1 executable 36 // region of memory. 37 t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping)) 38 } 39 address1 := mprof.Mapping[0].Start 40 address2 := mprof.Mapping[1].Start 41 42 var buf bytes.Buffer 43 44 rec, rate := testMemRecords(address1, address2) 45 p := encodeMemProfile(rec, rate, time.Now()) 46 if err := p.Write(&buf); err != nil { 47 t.Fatalf("Failed to write profile: %v", err) 48 } 49 50 p, err = profile.Parse(&buf) 51 if err != nil { 52 t.Fatalf("Could not parse Profile profile: %v", err) 53 } 54 55 // Expected PeriodType, SampleType and Sample. 56 expectedPeriodType := &profile.ValueType{Type: "space", Unit: "bytes"} 57 expectedSampleType := []*profile.ValueType{ 58 {Type: "alloc_objects", Unit: "count"}, 59 {Type: "alloc_space", Unit: "bytes"}, 60 {Type: "inuse_objects", Unit: "count"}, 61 {Type: "inuse_space", Unit: "bytes"}, 62 } 63 // Expected samples, with values unsampled according to the profiling rate. 64 expectedSample := []*profile.Sample{ 65 {Value: []int64{2050, 2099200, 1537, 1574400}, Location: []*profile.Location{ 66 {ID: 1, Mapping: mprof.Mapping[0], Address: address1}, 67 {ID: 2, Mapping: mprof.Mapping[1], Address: address2}, 68 }}, 69 {Value: []int64{1, 829411, 1, 829411}, Location: []*profile.Location{ 70 {ID: 3, Mapping: mprof.Mapping[1], Address: address2 + 1}, 71 {ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 2}, 72 }}, 73 {Value: []int64{1, 829411, 0, 0}, Location: []*profile.Location{ 74 {ID: 5, Mapping: mprof.Mapping[0], Address: address1 + 1}, 75 {ID: 6, Mapping: mprof.Mapping[0], Address: address1 + 2}, 76 {ID: 7, Mapping: mprof.Mapping[1], Address: address2 + 3}, 77 }}, 78 } 79 80 if p.Period != 512*1024 { 81 t.Fatalf("Sampling periods do not match") 82 } 83 if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) { 84 t.Fatalf("Period types do not match") 85 } 86 if !reflect.DeepEqual(p.SampleType, expectedSampleType) { 87 t.Fatalf("Sample types do not match") 88 } 89 if !reflect.DeepEqual(p.Sample, expectedSample) { 90 t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample), 91 getSampleAsString(p.Sample)) 92 } 93 } 94 95 func testMemRecords(a1, a2 uint64) ([]runtime.MemProfileRecord, int64) { 96 addr1, addr2 := uintptr(a1), uintptr(a2) 97 rate := int64(512 * 1024) 98 rec := []runtime.MemProfileRecord{ 99 {AllocBytes: 4096, FreeBytes: 1024, AllocObjects: 4, FreeObjects: 1, Stack0: [32]uintptr{addr1, addr2}}, 100 {AllocBytes: 512 * 1024, FreeBytes: 0, AllocObjects: 1, FreeObjects: 0, Stack0: [32]uintptr{addr2 + 1, addr2 + 2}}, 101 {AllocBytes: 512 * 1024, FreeBytes: 512 * 1024, AllocObjects: 1, FreeObjects: 1, Stack0: [32]uintptr{addr1 + 1, addr1 + 2, addr2 + 3}}, 102 } 103 return rec, rate 104 }