Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
package cond
import (
"runtime"
"sync"
"sync/atomic"
"testing"
)
type Queue interface {
EnqueueRequest()
NextRequestToSend() bool
}
const size = 64
const mask = size - 1
type ring struct {
_ [8]uint64
write uint64
_ [7]uint64
read1 uint64
_ [7]uint64
slots [size]slot
}
type slot struct {
cond sync.Cond
mark uint32
}
func NewRing() *ring {
r := &ring{}
for i := 0; i < size; i++ {
r.slots[i].cond.L = &sync.Mutex{}
}
return r
}
func (r *ring) EnqueueRequest() {
s := &r.slots[atomic.AddUint64(&r.write, 1)&mask]
s.cond.L.Lock()
for s.mark != 0 {
s.cond.Wait()
}
s.mark = 1
s.cond.L.Unlock()
}
func (r *ring) NextRequestToSend() (ret bool) {
r.read1++
s := &r.slots[r.read1&mask]
s.cond.L.Lock()
if ret = s.mark == 1; ret {
s.mark = 0
} else {
r.read1--
}
s.cond.L.Unlock()
s.cond.Signal()
return ret
}
type channel struct {
ch chan struct{}
}
func (c *channel) EnqueueRequest() {
c.ch <- struct{}{}
}
func (c *channel) NextRequestToSend() bool {
select {
case <-c.ch:
return true
default:
return false
}
}
func BenchmarkCond(b *testing.B) {
bench := func(name string, parallelism int, mk func() Queue) {
b.Run(name, func(b *testing.B) {
q := mk()
s := uint32(0)
done := make(chan struct{})
go func() {
for atomic.LoadUint32(&s) == 0 {
if !q.NextRequestToSend() {
runtime.Gosched()
}
}
close(done)
}()
b.ResetTimer()
b.SetParallelism(parallelism)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
q.EnqueueRequest()
}
})
b.StopTimer()
if c, ok := q.(*channel); ok {
close(c.ch)
}
atomic.StoreUint32(&s, 1)
<-done
})
}
bench("Chan-size-64-parallelism-01", 1, func() Queue { return &channel{ch: make(chan struct{}, size)} })
bench("Ring-size-64-parallelism-01", 1, func() Queue { return NewRing() })
bench("Chan-size-64-parallelism-08", 8, func() Queue { return &channel{ch: make(chan struct{}, size)} })
bench("Ring-size-64-parallelism-08", 8, func() Queue { return NewRing() })
bench("Chan-size-64-parallelism-64", 64, func() Queue { return &channel{ch: make(chan struct{}, size)} })
bench("Ring-size-64-parallelism-64", 64, func() Queue { return NewRing() })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment