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:
parent
cf3eeb2984
commit
5c15f8710c
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user