Skip to content

Commit 9519651

Browse files
committed
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 <[email protected]> Run-TryBot: Michael Pratt <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent ecd2e14 commit 9519651

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

src/runtime/pprof/pprof_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,30 @@ func TestCPUProfileMultithreadMagnitude(t *testing.T) {
116116
t.Skip("issue 35057 is only confirmed on Linux")
117117
}
118118

119+
// Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly
120+
// created threads, breaking our CPU accounting.
121+
major, minor, patch, err := linuxKernelVersion()
122+
if err != nil {
123+
t.Errorf("Error determining kernel version: %v", err)
124+
}
125+
t.Logf("Running on Linux %d.%d.%d", major, minor, patch)
126+
defer func() {
127+
if t.Failed() {
128+
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.")
129+
}
130+
}()
131+
132+
// Disable on affected builders to avoid flakiness, but otherwise keep
133+
// it enabled to potentially warn users that they are on a broken
134+
// kernel.
135+
if testenv.Builder() != "" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64") {
136+
have59 := major > 5 || (major == 5 && minor >= 9)
137+
have516 := major > 5 || (major == 5 && minor >= 16)
138+
if have59 && !have516 {
139+
testenv.SkipFlaky(t, 49065)
140+
}
141+
}
142+
119143
// Run a workload in a single goroutine, then run copies of the same
120144
// workload in several goroutines. For both the serial and parallel cases,
121145
// the CPU time the process measures with its own profiler should match the
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build linux
6+
7+
package pprof
8+
9+
import (
10+
"fmt"
11+
"regexp"
12+
"strconv"
13+
"syscall"
14+
)
15+
16+
var versionRe = regexp.MustCompile(`^(\d+)(?:\.(\d+)(?:\.(\d+))).*$`)
17+
18+
func linuxKernelVersion() (major, minor, patch int, err error) {
19+
var uname syscall.Utsname
20+
if err := syscall.Uname(&uname); err != nil {
21+
return 0, 0, 0, err
22+
}
23+
24+
buf := make([]byte, 0, len(uname.Release))
25+
for _, b := range uname.Release {
26+
if b == 0 {
27+
break
28+
}
29+
buf = append(buf, byte(b))
30+
}
31+
rl := string(buf)
32+
33+
m := versionRe.FindStringSubmatch(rl)
34+
if m == nil {
35+
return 0, 0, 0, fmt.Errorf("error matching version number in %q", rl)
36+
}
37+
38+
v, err := strconv.ParseInt(m[1], 10, 64)
39+
if err != nil {
40+
return 0, 0, 0, fmt.Errorf("error parsing major version %q in %s: %w", m[1], rl, err)
41+
}
42+
major = int(v)
43+
44+
if len(m) >= 3 {
45+
v, err := strconv.ParseInt(m[2], 10, 64)
46+
if err != nil {
47+
return 0, 0, 0, fmt.Errorf("error parsing minor version %q in %s: %w", m[2], rl, err)
48+
}
49+
minor = int(v)
50+
}
51+
52+
if len(m) >= 4 {
53+
v, err := strconv.ParseInt(m[3], 10, 64)
54+
if err != nil {
55+
return 0, 0, 0, fmt.Errorf("error parsing patch version %q in %s: %w", m[3], rl, err)
56+
}
57+
patch = int(v)
58+
}
59+
60+
return
61+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !linux
6+
7+
package pprof
8+
9+
import (
10+
"errors"
11+
)
12+
13+
func linuxKernelVersion() (major, minor, patch int, err error) {
14+
return 0, 0, 0, errors.New("not running on linux")
15+
}

0 commit comments

Comments
 (0)