From 625d8e9b9cd7ede188a8856c5ac88791333baa63 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 13 Nov 2025 00:09:05 +0000 Subject: [PATCH] runtime/pprof: fix goroutine leak profile tests for noopt The goroutine leak profile tests currently rely on a function being inlined, which results in a slightly different representation in the pprof proto. This function is not inlined on the noopt builder. Disable inlining of the one function which could be inlined to align but the regular and noopt builder versions of this test. We're not interested in testing the inlining functionality of profiles with this test, we care about certain stack frames appearing in a certain order. This also simplifies a bunch of the checking in the test. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-noopt Change-Id: I28902cc4c9fae32d1e3fa41b93b00c3be4d6074a Reviewed-on: https://go-review.googlesource.com/c/go/+/720100 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/runtime/pprof/pprof_test.go | 37 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index c1d4f06595..4c9279c5a6 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -1569,6 +1569,9 @@ func containsCountsLabels(prof *profile.Profile, countLabels map[int64]map[strin return true } +// Inlining disabled to make identification simpler. +// +//go:noinline func goroutineLeakExample() { <-make(chan struct{}) panic("unreachable") @@ -1595,12 +1598,12 @@ func TestGoroutineLeakProfileConcurrency(t *testing.T) { checkFrame := func(i int, j int, locations []*profile.Location, expectedFunctionName string) { if len(locations) <= i { - t.Errorf("leaked goroutine stack locations out of range at %d of %d", i+1, len(locations)) + t.Errorf("leaked goroutine stack locations: out of range index %d, length %d", i, len(locations)) return } location := locations[i] if len(location.Line) <= j { - t.Errorf("leaked goroutine stack location lines out of range at %d of %d", j+1, len(location.Line)) + t.Errorf("leaked goroutine stack location lines: out of range index %d, length %d", j, len(location.Line)) return } if location.Line[j].Function.Name != expectedFunctionName { @@ -1650,26 +1653,7 @@ func TestGoroutineLeakProfileConcurrency(t *testing.T) { t.Errorf("expected %d leaked goroutines with specific stack configurations, but found %d", leakCount, pc) return } - switch len(locations) { - case 4: - // We expect a receive operation. This is the typical stack. - checkFrame(0, 0, locations, "runtime.gopark") - checkFrame(1, 0, locations, "runtime.chanrecv") - checkFrame(2, 0, locations, "runtime.chanrecv1") - switch len(locations[3].Line) { - case 2: - // Running `go func() { goroutineLeakExample() }()` will produce a stack with 2 lines. - // The anonymous function will have the call to goroutineLeakExample inlined. - checkFrame(3, 1, locations, "runtime/pprof.TestGoroutineLeakProfileConcurrency.func5") - fallthrough - case 1: - // Running `go goroutineLeakExample()` will produce a stack with 1 line. - checkFrame(3, 0, locations, "runtime/pprof.goroutineLeakExample") - default: - t.Errorf("leaked goroutine stack location expected 1 or 2 lines in the 4th location but found %d", len(locations[3].Line)) - return - } - default: + if len(locations) < 4 || len(locations) > 5 { message := fmt.Sprintf("leaked goroutine stack expected 4 or 5 locations but found %d", len(locations)) for _, location := range locations { for _, line := range location.Line { @@ -1677,6 +1661,15 @@ func TestGoroutineLeakProfileConcurrency(t *testing.T) { } } t.Errorf("%s", message) + return + } + // We expect a receive operation. This is the typical stack. + checkFrame(0, 0, locations, "runtime.gopark") + checkFrame(1, 0, locations, "runtime.chanrecv") + checkFrame(2, 0, locations, "runtime.chanrecv1") + checkFrame(3, 0, locations, "runtime/pprof.goroutineLeakExample") + if len(locations) == 5 { + checkFrame(4, 0, locations, "runtime/pprof.TestGoroutineLeakProfileConcurrency.func5") } } } -- 2.52.0