From 1fe2810f9ca0dcd34e473f852102e2a49d45d7d8 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 10 Jun 2022 16:21:46 +0000 Subject: 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 --- src/sync/mutex_test.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'src/sync') 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() + } + } + }) +} -- cgit v1.3-5-g9baa