1
0
mirror of https://github.com/golang/go synced 2024-11-19 14:34:42 -07:00

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
This commit is contained in:
Dmitriy Vyukov 2011-06-28 08:14:54 -04:00 committed by Russ Cox
parent cf3eeb2984
commit 5c15f8710c

View 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)
}