diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2022-06-10 16:21:46 +0000 |
|---|---|---|
| committer | Michael Knyszek <mknyszek@google.com> | 2022-06-13 20:15:55 +0000 |
| commit | 1fe2810f9ca0dcd34e473f852102e2a49d45d7d8 (patch) | |
| tree | 429e31e7529c6066e3529e96078107f85afce083 /src/sync | |
| parent | 6130461149020d2b4b91fb183afa388a211cadc5 (diff) | |
| download | go-1fe2810f9ca0dcd34e473f852102e2a49d45d7d8.tar.xz | |
sync: move lock linearity test and treat it like a performance test
This change moves test/locklinear.go into the sync package tests, and
adds a bit of infrastructure since there are other linearity-checking
tests that could benefit from it too. This infrastructure is also
different than what test/locklinear.go does: instead of trying really
hard to get at least one success, we instead treat this like a
performance test and look for a significant difference via a t-test.
This makes the methodology behind the tests more rigorous, and should
reduce flakiness as transient noise should produce an insignificant
result. A follow-up CL does more to make these tests even more robust.
For #32986.
Change-Id: I408c5f643962b70ea708930edb4ac9df1c6123ce
Reviewed-on: https://go-review.googlesource.com/c/go/+/411396
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/sync')
| -rw-r--r-- | src/sync/mutex_test.go | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go index cca0986a30..9a4187c672 100644 --- a/src/sync/mutex_test.go +++ b/src/sync/mutex_test.go @@ -333,3 +333,93 @@ func BenchmarkMutexSpin(b *testing.B) { } }) } + +const runtimeSemaHashTableSize = 251 // known size of runtime hash table + +func TestMutexLinearOne(t *testing.T) { + testenv.CheckLinear(t, func(scale float64) func(*testing.B) { + n := int(1000 * scale) + return func(b *testing.B) { + ch := make(chan int) + locks := make([]RWMutex, runtimeSemaHashTableSize+1) + for i := 0; i < n; i++ { + go func() { + locks[0].Lock() + ch <- 1 + }() + } + time.Sleep(1 * time.Millisecond) + + go func() { + for j := 0; j < n; j++ { + locks[1].Lock() + locks[runtimeSemaHashTableSize].Lock() + locks[1].Unlock() + runtime.Gosched() + locks[runtimeSemaHashTableSize].Unlock() + } + }() + + for j := 0; j < n; j++ { + locks[1].Lock() + locks[runtimeSemaHashTableSize].Lock() + locks[1].Unlock() + runtime.Gosched() + locks[runtimeSemaHashTableSize].Unlock() + } + + for i := 0; i < n; i++ { + <-ch + locks[0].Unlock() + } + } + }) +} + +func TestMutexLinearMany(t *testing.T) { + if runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" { + // stressLockMany reliably fails on the linux-arm-arm5spacemonkey + // builder. See https://golang.org/issue/24221. + return + } + testenv.CheckLinear(t, func(scale float64) func(*testing.B) { + n := int(1000 * scale) + return func(b *testing.B) { + locks := make([]RWMutex, n*runtimeSemaHashTableSize+1) + + var wg WaitGroup + for i := 0; i < n; i++ { + wg.Add(1) + go func(i int) { + locks[(i+1)*runtimeSemaHashTableSize].Lock() + wg.Done() + locks[(i+1)*runtimeSemaHashTableSize].Lock() + locks[(i+1)*runtimeSemaHashTableSize].Unlock() + }(i) + } + wg.Wait() + + go func() { + for j := 0; j < n; j++ { + locks[1].Lock() + locks[0].Lock() + locks[1].Unlock() + runtime.Gosched() + locks[0].Unlock() + } + }() + + for j := 0; j < n; j++ { + locks[1].Lock() + locks[0].Lock() + locks[1].Unlock() + runtime.Gosched() + locks[0].Unlock() + } + + for i := 0; i < n; i++ { + locks[(i+1)*runtimeSemaHashTableSize].Unlock() + } + } + }) +} |
