Skip to content

Commit

Permalink
test: improve runtime/pprof tests for gccgo
Browse files Browse the repository at this point in the history
In the CPU profile tests for gccgo, check to make sure that the
runtime's sigprof handler itself doesn't appear in the profile. Add a
"skip if gccgo" guard to one testpoint.

Updates #26595

Change-Id: I92a44161d61f17b9305ce09532134edd229745a7
Reviewed-on: https://go-review.googlesource.com/126316
Run-TryBot: Than McIntosh <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
thanm committed Aug 31, 2018
1 parent dbd8af7 commit 88206b8
Showing 1 changed file with 42 additions and 11 deletions.
53 changes: 42 additions & 11 deletions src/runtime/pprof/pprof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,24 @@ func cpuHog2(x int) int {
return foo
}

// Return a list of functions that we don't want to ever appear in CPU
// profiles. For gccgo, that list includes the sigprof handler itself.
func avoidFunctions() []string {
if runtime.Compiler == "gccgo" {
return []string{"runtime.sigprof"}
}
return nil
}

func TestCPUProfile(t *testing.T) {
testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1"}, func(dur time.Duration) {
testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1"}, avoidFunctions(), func(dur time.Duration) {
cpuHogger(cpuHog1, &salt1, dur)
})
}

func TestCPUProfileMultithreaded(t *testing.T) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog2"}, func(dur time.Duration) {
testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog2"}, avoidFunctions(), func(dur time.Duration) {
c := make(chan int)
go func() {
cpuHogger(cpuHog1, &salt1, dur)
Expand All @@ -92,7 +101,7 @@ func TestCPUProfileMultithreaded(t *testing.T) {
}

func TestCPUProfileInlining(t *testing.T) {
testCPUProfile(t, stackContains, []string{"runtime/pprof.inlinedCallee", "runtime/pprof.inlinedCaller"}, func(dur time.Duration) {
testCPUProfile(t, stackContains, []string{"runtime/pprof.inlinedCallee", "runtime/pprof.inlinedCaller"}, avoidFunctions(), func(dur time.Duration) {
cpuHogger(inlinedCaller, &salt1, dur)
})
}
Expand Down Expand Up @@ -132,7 +141,7 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca

// testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need,
// as interpreted by matches.
func testCPUProfile(t *testing.T, matches matchFunc, need []string, f func(dur time.Duration)) {
func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []string, f func(dur time.Duration)) {
switch runtime.GOOS {
case "darwin":
switch runtime.GOARCH {
Expand Down Expand Up @@ -171,7 +180,7 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, f func(dur t
f(duration)
StopCPUProfile()

if profileOk(t, need, matches, prof, duration) {
if profileOk(t, matches, need, avoid, prof, duration) {
return
}

Expand Down Expand Up @@ -218,11 +227,13 @@ func stackContains(spec string, count uintptr, stk []*profile.Location, labels m

type matchFunc func(spec string, count uintptr, stk []*profile.Location, labels map[string][]string) bool

func profileOk(t *testing.T, need []string, matches matchFunc, prof bytes.Buffer, duration time.Duration) (ok bool) {
func profileOk(t *testing.T, matches matchFunc, need []string, avoid []string, prof bytes.Buffer, duration time.Duration) (ok bool) {
ok = true

// Check that profile is well formed and contains need.
// Check that profile is well formed, contains 'need', and does not contain
// anything from 'avoid'.
have := make([]uintptr, len(need))
avoidSamples := make([]uintptr, len(avoid))
var samples uintptr
var buf bytes.Buffer
parseProfile(t, prof.Bytes(), func(count uintptr, stk []*profile.Location, labels map[string][]string) {
Expand All @@ -234,6 +245,15 @@ func profileOk(t *testing.T, need []string, matches matchFunc, prof bytes.Buffer
have[i] += count
}
}
for i, name := range avoid {
for _, loc := range stk {
for _, line := range loc.Line {
if strings.Contains(line.Function.Name, name) {
avoidSamples[i] += count
}
}
}
}
fmt.Fprintf(&buf, "\n")
})
t.Logf("total %d CPU profile samples collected:\n%s", samples, buf.String())
Expand All @@ -256,6 +276,14 @@ func profileOk(t *testing.T, need []string, matches matchFunc, prof bytes.Buffer
ok = false
}

for i, name := range avoid {
bad := avoidSamples[i]
if bad != 0 {
t.Logf("found %d samples in avoid-function %s\n", bad, name)
ok = false
}
}

if len(need) == 0 {
return ok
}
Expand Down Expand Up @@ -323,6 +351,9 @@ func TestCPUProfileWithFork(t *testing.T) {
// If it did, it would see inconsistent state and would either record an incorrect stack
// or crash because the stack was malformed.
func TestGoroutineSwitch(t *testing.T) {
if runtime.Compiler == "gccgo" {
t.Skip("not applicable for gccgo")
}
// How much to try. These defaults take about 1 seconds
// on a 2012 MacBook Pro. The ones in short mode take
// about 0.1 seconds.
Expand Down Expand Up @@ -382,7 +413,7 @@ func fprintStack(w io.Writer, stk []*profile.Location) {

// Test that profiling of division operations is okay, especially on ARM. See issue 6681.
func TestMathBigDivide(t *testing.T) {
testCPUProfile(t, nil, nil, func(duration time.Duration) {
testCPUProfile(t, nil, nil, nil, func(duration time.Duration) {
t := time.After(duration)
pi := new(big.Int)
for {
Expand Down Expand Up @@ -411,7 +442,7 @@ func stackContainsAll(spec string, count uintptr, stk []*profile.Location, label
}

func TestMorestack(t *testing.T) {
testCPUProfile(t, stackContainsAll, []string{"runtime.newstack,runtime/pprof.growstack"}, func(duration time.Duration) {
testCPUProfile(t, stackContainsAll, []string{"runtime.newstack,runtime/pprof.growstack"}, avoidFunctions(), func(duration time.Duration) {
t := time.After(duration)
c := make(chan bool)
for {
Expand Down Expand Up @@ -913,7 +944,7 @@ func stackContainsLabeled(spec string, count uintptr, stk []*profile.Location, l
}

func TestCPUProfileLabel(t *testing.T) {
testCPUProfile(t, stackContainsLabeled, []string{"runtime/pprof.cpuHogger;key=value"}, func(dur time.Duration) {
testCPUProfile(t, stackContainsLabeled, []string{"runtime/pprof.cpuHogger;key=value"}, avoidFunctions(), func(dur time.Duration) {
Do(context.Background(), Labels("key", "value"), func(context.Context) {
cpuHogger(cpuHog1, &salt1, dur)
})
Expand All @@ -924,7 +955,7 @@ func TestLabelRace(t *testing.T) {
// Test the race detector annotations for synchronization
// between settings labels and consuming them from the
// profile.
testCPUProfile(t, stackContainsLabeled, []string{"runtime/pprof.cpuHogger;key=value"}, func(dur time.Duration) {
testCPUProfile(t, stackContainsLabeled, []string{"runtime/pprof.cpuHogger;key=value"}, nil, func(dur time.Duration) {
start := time.Now()
var wg sync.WaitGroup
for time.Since(start) < dur {
Expand Down

0 comments on commit 88206b8

Please sign in to comment.