]> Cypherpunks repositories - gostls13.git/commitdiff
sync: replace Mutex benchmarks
authorDmitriy Vyukov <dvyukov@google.com>
Tue, 28 Jun 2011 12:14:54 +0000 (08:14 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 28 Jun 2011 12:14:54 +0000 (08:14 -0400)
For both contended and uncontended case:
 - support arbitrary number of cpus (not just 2)
 - dynamic load balancing (improves stability)
 - periodic execution of Gosched() to work around non-preemptiviness
For uncontended case eliminates possible false-sharing.
For contended case includes additional variation with some
amount of local work between mutex operations.

R=r, rsc
CC=golang-dev
https://golang.org/cl/4634093

src/pkg/sync/mutex_test.go

index 9bfdec365fbd2d958db63082b970405a96ce00c8..d5ada8567338933041d7cccabef8368f5f22c30c 100644 (file)
@@ -9,6 +9,7 @@ package sync_test
 import (
        "runtime"
        . "sync"
+       "sync/atomic"
        "testing"
 )
 
@@ -72,24 +73,6 @@ func TestMutex(t *testing.T) {
        }
 }
 
-func BenchmarkUncontendedMutex(b *testing.B) {
-       m := new(Mutex)
-       HammerMutex(m, b.N, make(chan bool, 2))
-}
-
-func BenchmarkContendedMutex(b *testing.B) {
-       b.StopTimer()
-       m := new(Mutex)
-       c := make(chan bool)
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
-       b.StartTimer()
-
-       go HammerMutex(m, b.N/2, c)
-       go HammerMutex(m, b.N/2, c)
-       <-c
-       <-c
-}
-
 func TestMutexPanic(t *testing.T) {
        defer func() {
                if recover() == nil {
@@ -102,3 +85,83 @@ func TestMutexPanic(t *testing.T) {
        mu.Unlock()
        mu.Unlock()
 }
+
+func BenchmarkMutexUncontended(b *testing.B) {
+       type PaddedMutex struct {
+               Mutex
+               pad [128]uint8
+       }
+       const CallsPerSched = 1000
+       procs := runtime.GOMAXPROCS(-1)
+       N := int32(b.N / CallsPerSched)
+       c := make(chan bool, procs)
+       for p := 0; p < procs; p++ {
+               go func() {
+                       var mu PaddedMutex
+                       for atomic.AddInt32(&N, -1) >= 0 {
+                               runtime.Gosched()
+                               for g := 0; g < CallsPerSched; g++ {
+                                       mu.Lock()
+                                       mu.Unlock()
+                               }
+                       }
+                       c <- true
+               }()
+       }
+       for p := 0; p < procs; p++ {
+               <-c
+       }
+}
+
+func benchmarkMutex(b *testing.B, slack, work bool) {
+       const (
+               CallsPerSched  = 1000
+               LocalWork      = 100
+               GoroutineSlack = 10
+       )
+       procs := runtime.GOMAXPROCS(-1)
+       if slack {
+               procs *= GoroutineSlack
+       }
+       N := int32(b.N / CallsPerSched)
+       c := make(chan bool, procs)
+       var mu Mutex
+       for p := 0; p < procs; p++ {
+               go func() {
+                       foo := 0
+                       for atomic.AddInt32(&N, -1) >= 0 {
+                               runtime.Gosched()
+                               for g := 0; g < CallsPerSched; g++ {
+                                       mu.Lock()
+                                       mu.Unlock()
+                                       if work {
+                                               for i := 0; i < LocalWork; i++ {
+                                                       foo *= 2
+                                                       foo /= 2
+                                               }
+                                       }
+                               }
+                       }
+                       c <- foo == 42
+               }()
+       }
+       for p := 0; p < procs; p++ {
+               <-c
+       }
+}
+
+func BenchmarkMutex(b *testing.B) {
+       benchmarkMutex(b, false, false)
+}
+
+func BenchmarkMutexSlack(b *testing.B) {
+       benchmarkMutex(b, true, false)
+}
+
+func BenchmarkMutexWork(b *testing.B) {
+       benchmarkMutex(b, false, true)
+}
+
+func BenchmarkMutexWorkSlack(b *testing.B) {
+       benchmarkMutex(b, true, true)
+}