Home | History | Annotate | Download | only in protopprof
      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 protopprof
      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 		{4096, 1024, 4, 1, [32]uintptr{addr1, addr2}},
    100 		{512 * 1024, 0, 1, 0, [32]uintptr{addr2 + 1, addr2 + 2}},
    101 		{512 * 1024, 512 * 1024, 1, 1, [32]uintptr{addr1 + 1, addr1 + 2, addr2 + 3}},
    102 	}
    103 	return rec, rate
    104 }
    105