Commit d1ac5927 authored by Russ Cox's avatar Russ Cox

runtime/pprof: add /proc/self/maps parsing test

Delete old TestRuntimeFunctionTrimming, which is testing a dead API
and is now handled in end-to-end tests.

Change-Id: I64fc2991ed4a7690456356b5f6b546f36935bb67
Reviewed-on: https://go-review.googlesource.com/41815
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMichael Matloob <matloob@golang.org>
parent c5b6c2ab
...@@ -370,7 +370,10 @@ func (b *profileBuilder) build() error { ...@@ -370,7 +370,10 @@ func (b *profileBuilder) build() error {
// when emitting locations. // when emitting locations.
func (b *profileBuilder) readMapping() { func (b *profileBuilder) readMapping() {
data, _ := ioutil.ReadFile("/proc/self/maps") data, _ := ioutil.ReadFile("/proc/self/maps")
parseProcSelfMaps(data, b.addMapping)
}
func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, buildID string)) {
// $ cat /proc/self/maps // $ cat /proc/self/maps
// 00400000-0040b000 r-xp 00000000 fc:01 787766 /bin/cat // 00400000-0040b000 r-xp 00000000 fc:01 787766 /bin/cat
// 0060a000-0060b000 r--p 0000a000 fc:01 787766 /bin/cat // 0060a000-0060b000 r--p 0000a000 fc:01 787766 /bin/cat
...@@ -456,7 +459,11 @@ func (b *profileBuilder) readMapping() { ...@@ -456,7 +459,11 @@ func (b *profileBuilder) readMapping() {
// enter the mappings into b.mem in the first place. // enter the mappings into b.mem in the first place.
buildID, _ := elfBuildID(file) buildID, _ := elfBuildID(file)
b.mem = append(b.mem, memMap{uintptr(lo), uintptr(hi)}) addMapping(lo, hi, offset, file, buildID)
b.pbMapping(tagProfile_Mapping, uint64(len(b.mem)), lo, hi, offset, file, buildID)
} }
} }
func (b *profileBuilder) addMapping(lo, hi, offset uint64, file, buildID string) {
b.mem = append(b.mem, memMap{uintptr(lo), uintptr(hi)})
b.pbMapping(tagProfile_Mapping, uint64(len(b.mem)), lo, hi, offset, file, buildID)
}
...@@ -7,10 +7,12 @@ package pprof ...@@ -7,10 +7,12 @@ package pprof
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"reflect" "reflect"
"runtime" "runtime"
"runtime/pprof/internal/profile" "runtime/pprof/internal/profile"
"strings"
"testing" "testing"
) )
...@@ -163,101 +165,47 @@ func checkProfile(t *testing.T, p *profile.Profile, period int64, periodType *pr ...@@ -163,101 +165,47 @@ func checkProfile(t *testing.T, p *profile.Profile, period int64, periodType *pr
} }
} }
type fakeFunc struct { var profSelfMapsTests = `
name string 00400000-0040b000 r-xp 00000000 fc:01 787766 /bin/cat
file string 0060a000-0060b000 r--p 0000a000 fc:01 787766 /bin/cat
lineno int 0060b000-0060c000 rw-p 0000b000 fc:01 787766 /bin/cat
} 014ab000-014cc000 rw-p 00000000 00:00 0 [heap]
7f7d76af8000-7f7d7797c000 r--p 00000000 fc:01 1318064 /usr/lib/locale/locale-archive
func (f *fakeFunc) Name() string { 7f7d7797c000-7f7d77b36000 r-xp 00000000 fc:01 1180226 /lib/x86_64-linux-gnu/libc-2.19.so
return f.name 7f7d77b36000-7f7d77d36000 ---p 001ba000 fc:01 1180226 /lib/x86_64-linux-gnu/libc-2.19.so
} 7f7d77d36000-7f7d77d3a000 r--p 001ba000 fc:01 1180226 /lib/x86_64-linux-gnu/libc-2.19.so
func (f *fakeFunc) FileLine(uintptr) (string, int) { 7f7d77d3a000-7f7d77d3c000 rw-p 001be000 fc:01 1180226 /lib/x86_64-linux-gnu/libc-2.19.so
return f.file, f.lineno 7f7d77d3c000-7f7d77d41000 rw-p 00000000 00:00 0
} 7f7d77d41000-7f7d77d64000 r-xp 00000000 fc:01 1180217 /lib/x86_64-linux-gnu/ld-2.19.so
7f7d77f3f000-7f7d77f42000 rw-p 00000000 00:00 0
/* 7f7d77f61000-7f7d77f63000 rw-p 00000000 00:00 0
// TestRuntimeFunctionTrimming tests if symbolize trims runtime functions as intended. 7f7d77f63000-7f7d77f64000 r--p 00022000 fc:01 1180217 /lib/x86_64-linux-gnu/ld-2.19.so
func TestRuntimeRunctionTrimming(t *testing.T) { 7f7d77f64000-7f7d77f65000 rw-p 00023000 fc:01 1180217 /lib/x86_64-linux-gnu/ld-2.19.so
fakeFuncMap := map[uintptr]*fakeFunc{ 7f7d77f65000-7f7d77f66000 rw-p 00000000 00:00 0
0x10: &fakeFunc{"runtime.goexit", "runtime.go", 10}, 7ffc342a2000-7ffc342c3000 rw-p 00000000 00:00 0 [stack]
0x20: &fakeFunc{"runtime.other", "runtime.go", 20}, 7ffc34343000-7ffc34345000 r-xp 00000000 00:00 0 [vdso]
0x30: &fakeFunc{"foo", "foo.go", 30}, ffffffffff600000-ffffffffff601000 r-xp 00000090 00:00 0 [vsyscall]
0x40: &fakeFunc{"bar", "bar.go", 40}, ->
} 00400000 0040b000 00000000 /bin/cat
backupFuncForPC := funcForPC 7f7d7797c000 7f7d77b36000 00000000 /lib/x86_64-linux-gnu/libc-2.19.so
funcForPC = func(pc uintptr) function { 7f7d77d41000 7f7d77d64000 00000000 /lib/x86_64-linux-gnu/ld-2.19.so
return fakeFuncMap[pc] 7ffc34343000 7ffc34345000 00000000 [vdso]
} ffffffffff600000 ffffffffff601000 00000090 [vsyscall]
defer func() { `
funcForPC = backupFuncForPC
}() func TestProcSelfMaps(t *testing.T) {
testLoc := []*profile.Location{ for tx, tt := range strings.Split(profSelfMapsTests, "\n\n") {
{ID: 1, Address: 0x10}, i := strings.Index(tt, "->\n")
{ID: 2, Address: 0x20}, if i < 0 {
{ID: 3, Address: 0x30}, t.Fatal("malformed test case")
{ID: 4, Address: 0x40}, }
} in, out := tt[:i], tt[i+len("->\n"):]
testProfile := &profile.Profile{ var buf bytes.Buffer
Sample: []*profile.Sample{ parseProcSelfMaps([]byte(in), func(lo, hi, offset uint64, file, buildID string) {
{Location: []*profile.Location{testLoc[0], testLoc[1], testLoc[3], testLoc[2]}}, fmt.Fprintf(&buf, "%08x %08x %08x %s\n", lo, hi, offset, file)
{Location: []*profile.Location{testLoc[1], testLoc[3], testLoc[2]}}, })
{Location: []*profile.Location{testLoc[3], testLoc[2], testLoc[1]}}, if buf.String() != out {
{Location: []*profile.Location{testLoc[3], testLoc[2], testLoc[0]}}, t.Errorf("#%d: have:\n%s\nwant:\n%s", tx, buf.String(), out)
{Location: []*profile.Location{testLoc[0], testLoc[1], testLoc[3], testLoc[0]}},
},
Location: testLoc,
}
testProfiles := make([]*profile.Profile, 2)
testProfiles[0] = testProfile.Copy()
testProfiles[1] = testProfile.Copy()
// Test case for profilez.
testProfiles[0].PeriodType = &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}
// Test case for heapz.
testProfiles[1].PeriodType = &profile.ValueType{Type: "space", Unit: "bytes"}
wantFunc := []*profile.Function{
{ID: 1, Name: "runtime.goexit", SystemName: "runtime.goexit", Filename: "runtime.go"},
{ID: 2, Name: "runtime.other", SystemName: "runtime.other", Filename: "runtime.go"},
{ID: 3, Name: "foo", SystemName: "foo", Filename: "foo.go"},
{ID: 4, Name: "bar", SystemName: "bar", Filename: "bar.go"},
}
wantLoc := []*profile.Location{
{ID: 1, Address: 0x10, Line: []profile.Line{{Function: wantFunc[0], Line: 10}}},
{ID: 2, Address: 0x20, Line: []profile.Line{{Function: wantFunc[1], Line: 20}}},
{ID: 3, Address: 0x30, Line: []profile.Line{{Function: wantFunc[2], Line: 30}}},
{ID: 4, Address: 0x40, Line: []profile.Line{{Function: wantFunc[3], Line: 40}}},
}
wantProfiles := []*profile.Profile{
{
PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"},
Sample: []*profile.Sample{
{Location: []*profile.Location{wantLoc[1], wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[1], wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[3], wantLoc[2], wantLoc[1]}},
{Location: []*profile.Location{wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[1], wantLoc[3]}},
},
Location: wantLoc,
Function: wantFunc,
},
{
PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"},
Sample: []*profile.Sample{
{Location: []*profile.Location{wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[3], wantLoc[2], wantLoc[1]}},
{Location: []*profile.Location{wantLoc[3], wantLoc[2]}},
{Location: []*profile.Location{wantLoc[3]}},
},
Location: wantLoc,
Function: wantFunc,
},
}
for i := 0; i < 2; i++ {
symbolize(testProfiles[i])
if !reflect.DeepEqual(testProfiles[i], wantProfiles[i]) {
t.Errorf("incorrect trimming (testcase = %d): got {%v}, want {%v}", i, testProfiles[i], wantProfiles[i])
} }
} }
} }
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment