summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/pprof/proto_test.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-09-24 21:46:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-09-24 21:46:21 +0000
commitdd931d9b48647e898dc80927c532ae93cc09e192 (patch)
tree71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/runtime/pprof/proto_test.go
parent779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff)
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435 gotools/: * Makefile.am (mostlyclean-local): Run chmod on check-go-dir to make sure it is writable. (check-go-tools): Likewise. (check-vet): Copy internal/objabi to check-vet-dir. * Makefile.in: Rebuild. From-SVN: r264546
Diffstat (limited to 'libgo/go/runtime/pprof/proto_test.go')
-rw-r--r--libgo/go/runtime/pprof/proto_test.go138
1 files changed, 132 insertions, 6 deletions
diff --git a/libgo/go/runtime/pprof/proto_test.go b/libgo/go/runtime/pprof/proto_test.go
index a268c3a95d9..604628ce457 100644
--- a/libgo/go/runtime/pprof/proto_test.go
+++ b/libgo/go/runtime/pprof/proto_test.go
@@ -8,7 +8,10 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "internal/testenv"
"io/ioutil"
+ "os"
+ "os/exec"
"reflect"
"runtime"
"runtime/pprof/internal/profile"
@@ -63,7 +66,7 @@ func TestConvertCPUProfileEmpty(t *testing.T) {
{Type: "cpu", Unit: "nanoseconds"},
}
- checkProfile(t, p, 2000*1000, periodType, sampleType, nil)
+ checkProfile(t, p, 2000*1000, periodType, sampleType, nil, "")
}
// For gccgo make these functions different so that gccgo doesn't
@@ -96,9 +99,16 @@ func testPCs(t *testing.T) (addr1, addr2 uint64, map1, map2 *profile.Mapping) {
addr2 = mprof.Mapping[1].Start
map2 = mprof.Mapping[1]
map2.BuildID, _ = elfBuildID(map2.File)
+ case "js":
+ addr1 = uint64(funcPC(f1))
+ addr2 = uint64(funcPC(f2))
default:
addr1 = uint64(funcPC(f1))
addr2 = uint64(funcPC(f2))
+ // Fake mapping - HasFunctions will be true because two PCs from Go
+ // will be fully symbolized.
+ fake := &profile.Mapping{ID: 1, HasFunctions: true}
+ map1, map2 = fake, fake
}
return
}
@@ -132,18 +142,23 @@ func TestConvertCPUProfile(t *testing.T) {
{ID: 4, Mapping: map2, Address: addr2 + 1},
}},
}
- checkProfile(t, p, period, periodType, sampleType, samples)
+ checkProfile(t, p, period, periodType, sampleType, samples, "")
}
-func checkProfile(t *testing.T, p *profile.Profile, period int64, periodType *profile.ValueType, sampleType []*profile.ValueType, samples []*profile.Sample) {
+func checkProfile(t *testing.T, p *profile.Profile, period int64, periodType *profile.ValueType, sampleType []*profile.ValueType, samples []*profile.Sample, defaultSampleType string) {
+ t.Helper()
+
if p.Period != period {
- t.Fatalf("p.Period = %d, want %d", p.Period, period)
+ t.Errorf("p.Period = %d, want %d", p.Period, period)
}
if !reflect.DeepEqual(p.PeriodType, periodType) {
- t.Fatalf("p.PeriodType = %v\nwant = %v", fmtJSON(p.PeriodType), fmtJSON(periodType))
+ t.Errorf("p.PeriodType = %v\nwant = %v", fmtJSON(p.PeriodType), fmtJSON(periodType))
}
if !reflect.DeepEqual(p.SampleType, sampleType) {
- t.Fatalf("p.SampleType = %v\nwant = %v", fmtJSON(p.SampleType), fmtJSON(sampleType))
+ t.Errorf("p.SampleType = %v\nwant = %v", fmtJSON(p.SampleType), fmtJSON(sampleType))
+ }
+ if defaultSampleType != p.DefaultSampleType {
+ t.Errorf("p.DefaultSampleType = %v\nwant = %v", p.DefaultSampleType, defaultSampleType)
}
// Clear line info since it is not in the expected samples.
// If we used f1 and f2 above, then the samples will have line info.
@@ -222,3 +237,114 @@ func TestProcSelfMaps(t *testing.T) {
}
}
}
+
+// TestMapping checkes the mapping section of CPU profiles
+// has the HasFunctions field set correctly. If all PCs included
+// in the samples are successfully symbolized, the corresponding
+// mapping entry (in this test case, only one entry) should have
+// its HasFunctions field set true.
+// The test generates a CPU profile that includes PCs from C side
+// that the runtime can't symbolize. See ./testdata/mappingtest.
+func TestMapping(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ testenv.MustHaveCGO(t)
+
+ prog := "./testdata/mappingtest/main.go"
+
+ // GoOnly includes only Go symbols that runtime will symbolize.
+ // Go+C includes C symbols that runtime will not symbolize.
+ for _, traceback := range []string{"GoOnly", "Go+C"} {
+ t.Run("traceback"+traceback, func(t *testing.T) {
+ cmd := exec.Command(testenv.GoToolPath(t), "run", prog)
+ if traceback != "GoOnly" {
+ cmd.Env = append(os.Environ(), "SETCGOTRACEBACK=1")
+ }
+ cmd.Stderr = new(bytes.Buffer)
+
+ out, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("failed to run the test program %q: %v\n%v", prog, err, cmd.Stderr)
+ }
+
+ prof, err := profile.Parse(bytes.NewReader(out))
+ if err != nil {
+ t.Fatalf("failed to parse the generated profile data: %v", err)
+ }
+ t.Logf("Profile: %s", prof)
+
+ hit := make(map[*profile.Mapping]bool)
+ miss := make(map[*profile.Mapping]bool)
+ for _, loc := range prof.Location {
+ if symbolized(loc) {
+ hit[loc.Mapping] = true
+ } else {
+ miss[loc.Mapping] = true
+ }
+ }
+ if len(miss) == 0 {
+ t.Log("no location with missing symbol info was sampled")
+ }
+
+ for _, m := range prof.Mapping {
+ if miss[m] && m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=true, but contains locations with failed symbolization", m)
+ continue
+ }
+ if !miss[m] && hit[m] && !m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=false, but all referenced locations from this lapping were symbolized successfully", m)
+ continue
+ }
+ }
+ })
+ }
+}
+
+func symbolized(loc *profile.Location) bool {
+ if len(loc.Line) == 0 {
+ return false
+ }
+ l := loc.Line[0]
+ f := l.Function
+ if l.Line == 0 || f == nil || f.Name == "" || f.Filename == "" {
+ return false
+ }
+ return true
+}
+
+// TestFakeMapping tests if at least one mapping exists
+// (including a fake mapping), and their HasFunctions bits
+// are set correctly.
+func TestFakeMapping(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Lookup("heap").WriteTo(&buf, 0); err != nil {
+ t.Fatalf("failed to write heap profile: %v", err)
+ }
+ prof, err := profile.Parse(&buf)
+ if err != nil {
+ t.Fatalf("failed to parse the generated profile data: %v", err)
+ }
+ t.Logf("Profile: %s", prof)
+ if len(prof.Mapping) == 0 {
+ t.Fatal("want profile with at least one mapping entry, got 0 mapping")
+ }
+
+ hit := make(map[*profile.Mapping]bool)
+ miss := make(map[*profile.Mapping]bool)
+ for _, loc := range prof.Location {
+ if symbolized(loc) {
+ hit[loc.Mapping] = true
+ } else {
+ miss[loc.Mapping] = true
+ }
+ }
+ for _, m := range prof.Mapping {
+ if miss[m] && m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=true, but contains locations with failed symbolization", m)
+ continue
+ }
+ if !miss[m] && hit[m] && !m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=false, but all referenced locations from this lapping were symbolized successfully", m)
+ continue
+ }
+ }
+}