]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/pprof: add a fake mapping when /proc/self/maps is unavailable
authorHana (Hyang-Ah) Kim <hyangah@gmail.com>
Fri, 13 Jul 2018 20:11:24 +0000 (16:11 -0400)
committerHyang-Ah Hana Kim <hyangah@gmail.com>
Mon, 16 Jul 2018 15:24:25 +0000 (15:24 +0000)
Profile's Mapping field is currently populated by reading /proc/self/maps.
On systems where /proc/self/maps is not available, the profile generated
by Go's runtime will not have any Mapping entry. Pprof command then adds
a fake entry and links all Location entries in the profile with the fake
entry to be used during symbolization.
https://github.com/google/pprof/blob/a8644067d5a3c9a6386e7c88fa4a3d9d37877ca3/internal/driver/fetch.go#L437

The fake entry is not enough to suppress the error or warning messages
pprof command produces. We need to tell pprof that Location entries are
symbolized already by Go runtime and pprof does not have to attempt to
perform further symbolization.

In #25743, we made Go runtime mark Mapping entries with HasFunctions=true
when all Location entries from the Mapping entries are successfully
symbolized. This change makes the Go runtime add a fake mapping entry,
otherwise the pprof command tool would add, and set the HasFunctions=true
following the same logic taken when the real mapping information is
available.

Updates #19790.
Fixes #26255. Tested pprof doesn't report the error message any more
for pure Go program.

Change-Id: Ib12b62e15073f5d6c80967e44b3e8709277c11bd
Reviewed-on: https://go-review.googlesource.com/123779
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/runtime/pprof/proto.go
src/runtime/pprof/proto_test.go

index 1cf3a5154f77473e0b47747e52df000d99cf0ad2..cbd0b8337641666632fe2d4168d01dd5acc09780 100644 (file)
@@ -54,6 +54,7 @@ type memMap struct {
        file, buildID string
 
        funcs symbolizeFlag
+       fake  bool // map entry was faked; /proc/self/maps wasn't available
 }
 
 // symbolizeFlag keeps track of symbolization result.
@@ -267,7 +268,7 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 {
                frame, more = frames.Next()
        }
        for i := range b.mem {
-               if b.mem[i].start <= addr && addr < b.mem[i].end {
+               if b.mem[i].start <= addr && addr < b.mem[i].end || b.mem[i].fake {
                        b.pb.uint64Opt(tagLocation_MappingID, uint64(i+1))
 
                        m := b.mem[i]
@@ -440,6 +441,12 @@ func (b *profileBuilder) build() {
 func (b *profileBuilder) readMapping() {
        data, _ := ioutil.ReadFile("/proc/self/maps")
        parseProcSelfMaps(data, b.addMapping)
+       if len(b.mem) == 0 { // pprof expects a map entry, so fake one.
+               b.addMappingEntry(0, 0, 0, "", "", true)
+               // TODO(hyangah): make addMapping return *memMap or
+               // take a memMap struct, and get rid of addMappingEntry
+               // that takes a bunch of positional arguments.
+       }
 }
 
 func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, buildID string)) {
@@ -540,11 +547,16 @@ func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file,
 }
 
 func (b *profileBuilder) addMapping(lo, hi, offset uint64, file, buildID string) {
+       b.addMappingEntry(lo, hi, offset, file, buildID, false)
+}
+
+func (b *profileBuilder) addMappingEntry(lo, hi, offset uint64, file, buildID string, fake bool) {
        b.mem = append(b.mem, memMap{
                start:   uintptr(lo),
                end:     uintptr(hi),
                offset:  offset,
                file:    file,
                buildID: buildID,
+               fake:    fake,
        })
 }
index 36c345b6d95ef11b6c7adc3c8a4025e5e16e470d..76bd46da028dbb13125246485283675dca1230b6 100644 (file)
@@ -97,9 +97,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
 }
@@ -301,3 +308,41 @@ func symbolized(loc *profile.Location) bool {
        }
        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
+               }
+       }
+}