From: Dmitriy Vyukov Date: Tue, 28 Jun 2011 12:14:54 +0000 (-0400) Subject: sync: replace Mutex benchmarks X-Git-Tag: weekly.2011-07-07~97 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5c15f8710cb570e27d1ccf04143d31c7bff52581;p=gostls13.git sync: replace Mutex benchmarks 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 --- diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go index 9bfdec365f..d5ada85673 100644 --- a/src/pkg/sync/mutex_test.go +++ b/src/pkg/sync/mutex_test.go @@ -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) +}