]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/pprof: skip checks for inlined functions when inlining is disabled
authorBryan C. Mills <bcmills@google.com>
Sat, 9 Nov 2019 02:50:35 +0000 (21:50 -0500)
committerBryan C. Mills <bcmills@google.com>
Mon, 11 Nov 2019 15:15:06 +0000 (15:15 +0000)
Fixes #35463

Change-Id: I29af27b77cc651395c20570943847729ff12586c
Reviewed-on: https://go-review.googlesource.com/c/go/+/206297
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/runtime/pprof/mprof_test.go
src/runtime/pprof/pprof_test.go

index 8bc1ae41f2e21c8881f803488cc9948acfdf58d9..1c0d2c6ea9b9ae7c9da798f36e8e3a860775841e 100644 (file)
@@ -151,6 +151,12 @@ func TestMemoryProfiler(t *testing.T) {
                                t.Fatalf("No matching stack entry for %q\n\nProfile:\n%v\n", test.stk, p)
                        }
                }
+
+               if !containsInlinedCall(TestMemoryProfiler, 4<<10) {
+                       t.Logf("Can't determine whether allocateTransient2MInline was inlined into TestMemoryProfiler.")
+                       return
+               }
+
                // Check the inlined function location is encoded correctly.
                for _, loc := range p.Location {
                        inlinedCaller, inlinedCallee := false, false
index b553baf3a95e066c54d52f07e7e92eb9e8c7472a..5cbe9ab7a8be11ecb8aafbf3d4378fefe5c17ef4 100644 (file)
@@ -16,6 +16,7 @@ import (
        "math/big"
        "os"
        "os/exec"
+       "reflect"
        "regexp"
        "runtime"
        "runtime/pprof/internal/profile"
@@ -104,7 +105,44 @@ func TestCPUProfileMultithreaded(t *testing.T) {
        })
 }
 
+// containsInlinedCall reports whether the function body for the function f is
+// known to contain an inlined function call within the first maxBytes bytes.
+func containsInlinedCall(f interface{}, maxBytes int) bool {
+       rf := reflect.ValueOf(f)
+       if rf.Kind() != reflect.Func {
+               panic(fmt.Sprintf("%T is not a function", f))
+       }
+       fFunc := runtime.FuncForPC(rf.Pointer())
+       if fFunc == nil || fFunc.Entry() == 0 {
+               panic("failed to locate function entry")
+       }
+
+       for offset := 0; offset < maxBytes; offset++ {
+               inner := runtime.FuncForPC(fFunc.Entry() + uintptr(offset))
+               if inner == nil {
+                       // No function known for this PC value.
+                       // It might simply be misaligned, so keep searching.
+                       continue
+               }
+               if inner.Entry() != fFunc.Entry() {
+                       // Scanned past f and didn't find any inlined functions.
+                       break
+               }
+               if inner.Name() != fFunc.Name() {
+                       // This PC has f as its entry-point, but is not f. Therefore, it must be a
+                       // function inlined into f.
+                       return true
+               }
+       }
+
+       return false
+}
+
 func TestCPUProfileInlining(t *testing.T) {
+       if !containsInlinedCall(inlinedCaller, 4<<10) {
+               t.Skipf("Can't determine whether inlinedCallee was inlined into inlinedCaller.")
+       }
+
        p := testCPUProfile(t, stackContains, []string{"runtime/pprof.inlinedCallee", "runtime/pprof.inlinedCaller"}, avoidFunctions(), func(dur time.Duration) {
                cpuHogger(inlinedCaller, &salt1, dur)
        })