aboutsummaryrefslogtreecommitdiff
path: root/src/sync
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2022-06-10 16:21:46 +0000
committerMichael Knyszek <mknyszek@google.com>2022-06-13 20:15:55 +0000
commit1fe2810f9ca0dcd34e473f852102e2a49d45d7d8 (patch)
tree429e31e7529c6066e3529e96078107f85afce083 /src/sync
parent6130461149020d2b4b91fb183afa388a211cadc5 (diff)
downloadgo-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.go90
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()
+ }
+ }
+ })
+}