1
0
mirror of https://github.com/golang/go synced 2024-11-17 20:04:47 -07:00

runtime/pprof: increase contention upper bound in TestMutexProfile

Currently TestMutexProfile expects contention to reported as somewhere
between 0.9x and 2.0x the expected amount introduced. While bounding
from below is fine (especially since the goroutine holding the mutex
doesn't even start to sleep until the required number of goroutines are
blocked on a mutex), bounding from above can easily lead to flakiness.
Delays and non-determinism can come from anywhere in the system,
and nevertheless clocks keep ticking. The result is that goroutines
could easily appear to be blocked on a mutex much longer than just the
sleep time.

However, the contention upper bound is still useful, especially for
identifying wildly incorrect values. Set the contention total to be
proportional to the total wall-time spent in the actual sampling mutex
block sampling portion of the code. This should be a generous
upper-bound on how much contention there could be, because it should in
theory capture any delays from the environment in it as well.

Still, rounding errors could be an issue, and on Windows the time
granularity is quite low (~15ms, or 15% of what each goroutine is
supposed to add to the mutex profile), so getting unlucky with where
time measurements fall within each tick could also be a problem. Add an
extra 10%, which seems to make it much less likely to fail in a Windows
gomote.

Fixes #62094.

Change-Id: I59a10a73affd077185dada8474b91d0bc43b4a43
Reviewed-on: https://go-review.googlesource.com/c/go/+/520635
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
Michael Anthony Knyszek 2023-08-17 18:36:00 +00:00 committed by Gopher Robot
parent b65e34f038
commit e8a767b609

View File

@ -1245,7 +1245,9 @@ func TestMutexProfile(t *testing.T) {
N = 100
D = 100 * time.Millisecond
)
start := time.Now()
blockMutexN(t, N, D)
blockMutexNTime := time.Since(start)
t.Run("debug=1", func(t *testing.T) {
var w strings.Builder
@ -1307,9 +1309,22 @@ func TestMutexProfile(t *testing.T) {
for _, s := range p.Sample {
total += s.Value[i]
}
// Want d to be at least N*D, but give some wiggle-room to avoid
// a test flaking. Set an upper-bound proportional to the total
// wall time spent in blockMutexN. Generally speaking, the total
// contention time could be arbitrarily high when considering
// OS scheduler delays, or any other delays from the environment:
// time keeps ticking during these delays. By making the upper
// bound proportional to the wall time in blockMutexN, in theory
// we're accounting for all these possible delays.
d := time.Duration(total)
if d < N*D*9/10 || d > N*D*2 { // want N*D but allow [0.9,2.0]*that.
t.Fatalf("profile samples total %v, want %v", d, N*D)
lo := time.Duration(N * D * 9 / 10)
hi := time.Duration(N) * blockMutexNTime * 11 / 10
if d < lo || d > hi {
for _, s := range p.Sample {
t.Logf("sample: %s", time.Duration(s.Value[i]))
}
t.Fatalf("profile samples total %v, want within range [%v, %v] (target: %v)", d, lo, hi, N*D)
}
})
}