mirror of
https://github.com/golang/go
synced 2024-11-26 02:57:57 -07:00
runtime: add direct benchmark of mutex contention
Measure throughput of a single mutex with all threads contending. Do not attempt to measure fairness/starvation. The ChanContended benchmark works somewhat well for this (interacting with the mutex is a large contributor to its results), but it's better to be clear about what we're attempting to measure. For #68578 Change-Id: Ie397b4c363bfcd5afddf796a81cd6c34ebf8551b Reviewed-on: https://go-review.googlesource.com/c/go/+/604375 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Auto-Submit: Rhys Hiltner <rhys.hiltner@gmail.com>
This commit is contained in:
parent
820d445876
commit
c8ccbcdde5
@ -564,6 +564,48 @@ func BenchmarkOSYield(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMutexContention(b *testing.B) {
|
||||
// Measure throughput of a single mutex with all threads contending
|
||||
//
|
||||
// Share a single counter across all threads. Progress from any thread is
|
||||
// progress for the benchmark as a whole. We don't measure or give points
|
||||
// for fairness here, arbitrary delay to any given thread's progress is
|
||||
// invisible and allowed.
|
||||
//
|
||||
// The cache line that holds the count value will need to move between
|
||||
// processors, but not as often as the cache line that holds the mutex. The
|
||||
// mutex protects access to the count value, which limits contention on that
|
||||
// cache line. This is a simple design, but it helps to make the behavior of
|
||||
// the benchmark clear. Most real uses of mutex will protect some number of
|
||||
// cache lines anyway.
|
||||
|
||||
var state struct {
|
||||
_ cpu.CacheLinePad
|
||||
lock Mutex
|
||||
_ cpu.CacheLinePad
|
||||
count atomic.Int64
|
||||
_ cpu.CacheLinePad
|
||||
}
|
||||
|
||||
procs := GOMAXPROCS(0)
|
||||
var wg sync.WaitGroup
|
||||
for range procs {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
Lock(&state.lock)
|
||||
ours := state.count.Add(1)
|
||||
Unlock(&state.lock)
|
||||
if ours >= int64(b.N) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkMutexHandoff(b *testing.B) {
|
||||
testcase := func(delay func(l *Mutex)) func(b *testing.B) {
|
||||
return func(b *testing.B) {
|
||||
@ -590,11 +632,11 @@ func BenchmarkMutexHandoff(b *testing.B) {
|
||||
// each other in a non-blocking way via the "turn" state.
|
||||
|
||||
var state struct {
|
||||
_ [cpu.CacheLinePadSize]byte
|
||||
_ cpu.CacheLinePad
|
||||
lock Mutex
|
||||
_ [cpu.CacheLinePadSize]byte
|
||||
_ cpu.CacheLinePad
|
||||
turn atomic.Int64
|
||||
_ [cpu.CacheLinePadSize]byte
|
||||
_ cpu.CacheLinePad
|
||||
}
|
||||
|
||||
var delta atomic.Int64
|
||||
|
Loading…
Reference in New Issue
Block a user