From: Michael Pratt Date: Wed, 10 Nov 2021 22:35:13 +0000 (-0500) Subject: runtime/pprof: mark TestCPUProfileMultithreadMagnitude as flaky X-Git-Tag: go1.18beta1~354 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=95196512b6163dbeff2e7ce5cea65072305905f2;p=gostls13.git runtime/pprof: mark TestCPUProfileMultithreadMagnitude as flaky The Linux kernel starting in 5.9 and fixed in 5.16 has a bug that can break CPU timer signal delivery on new new threads if the timer interrupt fires during handling of the clone system call. Broken CPU timer signal deliver will skew CPU profile results and cause this test to fail. There is currently no known workaround, so mark the test as flaky on builders with known broken kernels. For #49065 Change-Id: I37ceb9ea244869b0aab5cd9a36b27ca2f7e5d315 Reviewed-on: https://go-review.googlesource.com/c/go/+/363214 Trust: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Michael Knyszek --- diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 704c0c516d..d9be00d030 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -116,6 +116,30 @@ func TestCPUProfileMultithreadMagnitude(t *testing.T) { t.Skip("issue 35057 is only confirmed on Linux") } + // Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly + // created threads, breaking our CPU accounting. + major, minor, patch, err := linuxKernelVersion() + if err != nil { + t.Errorf("Error determining kernel version: %v", err) + } + t.Logf("Running on Linux %d.%d.%d", major, minor, patch) + defer func() { + if t.Failed() { + t.Logf("Failure of this test may indicate that your system suffers from a known Linux kernel bug fixed on newer kernels. See https://golang.org/issue/49065.") + } + }() + + // Disable on affected builders to avoid flakiness, but otherwise keep + // it enabled to potentially warn users that they are on a broken + // kernel. + if testenv.Builder() != "" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64") { + have59 := major > 5 || (major == 5 && minor >= 9) + have516 := major > 5 || (major == 5 && minor >= 16) + if have59 && !have516 { + testenv.SkipFlaky(t, 49065) + } + } + // Run a workload in a single goroutine, then run copies of the same // workload in several goroutines. For both the serial and parallel cases, // the CPU time the process measures with its own profiler should match the diff --git a/src/runtime/pprof/uname_linux_test.go b/src/runtime/pprof/uname_linux_test.go new file mode 100644 index 0000000000..8374c83f74 --- /dev/null +++ b/src/runtime/pprof/uname_linux_test.go @@ -0,0 +1,61 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux + +package pprof + +import ( + "fmt" + "regexp" + "strconv" + "syscall" +) + +var versionRe = regexp.MustCompile(`^(\d+)(?:\.(\d+)(?:\.(\d+))).*$`) + +func linuxKernelVersion() (major, minor, patch int, err error) { + var uname syscall.Utsname + if err := syscall.Uname(&uname); err != nil { + return 0, 0, 0, err + } + + buf := make([]byte, 0, len(uname.Release)) + for _, b := range uname.Release { + if b == 0 { + break + } + buf = append(buf, byte(b)) + } + rl := string(buf) + + m := versionRe.FindStringSubmatch(rl) + if m == nil { + return 0, 0, 0, fmt.Errorf("error matching version number in %q", rl) + } + + v, err := strconv.ParseInt(m[1], 10, 64) + if err != nil { + return 0, 0, 0, fmt.Errorf("error parsing major version %q in %s: %w", m[1], rl, err) + } + major = int(v) + + if len(m) >= 3 { + v, err := strconv.ParseInt(m[2], 10, 64) + if err != nil { + return 0, 0, 0, fmt.Errorf("error parsing minor version %q in %s: %w", m[2], rl, err) + } + minor = int(v) + } + + if len(m) >= 4 { + v, err := strconv.ParseInt(m[3], 10, 64) + if err != nil { + return 0, 0, 0, fmt.Errorf("error parsing patch version %q in %s: %w", m[3], rl, err) + } + patch = int(v) + } + + return +} diff --git a/src/runtime/pprof/uname_other_test.go b/src/runtime/pprof/uname_other_test.go new file mode 100644 index 0000000000..327640755b --- /dev/null +++ b/src/runtime/pprof/uname_other_test.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux + +package pprof + +import ( + "errors" +) + +func linuxKernelVersion() (major, minor, patch int, err error) { + return 0, 0, 0, errors.New("not running on linux") +}