aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Joiner <anacrolix@gmail.com>2020-08-28 09:48:37 +1000
committerMatt Joiner <anacrolix@gmail.com>2020-08-28 09:48:37 +1000
commit900ed2bacafab432fc7a91811a7e5dbb93d44917 (patch)
tree8465594611720549277e153040d935b5d827c5e1
parentCount wakes for unchanged var version (diff)
downloadstm-900ed2bacafab432fc7a91811a7e5dbb93d44917.tar.gz
stm-900ed2bacafab432fc7a91811a7e5dbb93d44917.tar.xz
Add thundering herd tests
-rw-r--r--bench_test.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/bench_test.go b/bench_test.go
index 82aaba1..08faa96 100644
--- a/bench_test.go
+++ b/bench_test.go
@@ -149,3 +149,89 @@ func BenchmarkPingPong(b *testing.B) {
b.ReportAllocs()
parallelPingPongs(b, 1)
}
+
+const maxTokens = 25
+
+func BenchmarkThunderingHerdCondVar(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var mu sync.Mutex
+ consumer := sync.NewCond(&mu)
+ generator := sync.NewCond(&mu)
+ done := false
+ tokens := 0
+ var pending sync.WaitGroup
+ for range iter.N(1000) {
+ pending.Add(1)
+ go func() {
+ mu.Lock()
+ for {
+ if tokens > 0 {
+ tokens--
+ generator.Signal()
+ break
+ }
+ consumer.Wait()
+ }
+ mu.Unlock()
+ pending.Done()
+ }()
+ }
+ go func() {
+ mu.Lock()
+ for !done {
+ if tokens < maxTokens {
+ tokens++
+ consumer.Signal()
+ } else {
+ generator.Wait()
+ }
+ }
+ mu.Unlock()
+ }()
+ pending.Wait()
+ mu.Lock()
+ done = true
+ generator.Signal()
+ mu.Unlock()
+ }
+
+}
+
+func BenchmarkThunderingHerd(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ done := NewVar(false)
+ tokens := NewVar(0)
+ pending := NewVar(0)
+ for range iter.N(1000) {
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Set(pending, tx.Get(pending).(int)+1)
+ }))
+ go func() {
+ Atomically(VoidOperation(func(tx *Tx) {
+ t := tx.Get(tokens).(int)
+ if t > 0 {
+ tx.Set(tokens, t-1)
+ tx.Set(pending, tx.Get(pending).(int)-1)
+ } else {
+ tx.Retry()
+ }
+ }))
+ }()
+ }
+ go func() {
+ for Atomically(func(tx *Tx) interface{} {
+ if tx.Get(done).(bool) {
+ return false
+ }
+ tx.Assert(tx.Get(tokens).(int) < maxTokens)
+ tx.Set(tokens, tx.Get(tokens).(int)+1)
+ return true
+ }).(bool) {
+ }
+ }()
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(tx.Get(pending).(int) == 0)
+ }))
+ AtomicSet(done, true)
+ }
+}