Skip to content

Instantly share code, notes, and snippets.

@zach-klippenstein
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zach-klippenstein/93b0d9f0499b1597754f to your computer and use it in GitHub Desktop.
Save zach-klippenstein/93b0d9f0499b1597754f to your computer and use it in GitHub Desktop.
Comparative benchmarks of various methods of providing RNG sources to concurrent goroutines.
package source_bench_test
import (
"github.com/stretchr/testify/require"
"math/rand"
"sync"
"testing"
)
// See https://golang.org/src/math/rand/rand.go
type LockedSource struct {
lk sync.Mutex
src rand.Source
}
func NewLockedSource(seed int64) rand.Source {
return &LockedSource{src: rand.NewSource(seed)}
}
func (src *LockedSource) Int63() (n int64) {
src.lk.Lock()
n = src.src.Int63()
src.lk.Unlock()
return
}
func (src *LockedSource) Seed(seed int64) {
src.lk.Lock()
src.src.Seed(seed)
src.lk.Unlock()
}
type ChanBufferedSource chan int64
func NewChanBufferedSource(size int, seed int64) rand.Source {
source := rand.NewSource(seed)
sourceChan := make(chan int64, size)
go func() {
for {
sourceChan <- source.Int63()
}
}()
return ChanBufferedSource(sourceChan)
}
func (src ChanBufferedSource) Int63() int64 {
return <-src
}
func (src ChanBufferedSource) Seed(seed int64) {
panic("ChanBufferedSource doesn't support seeding")
}
type BufferedSource struct {
size int
src rand.Source
buffer []int64
lk sync.Mutex
}
func NewBufferedSource(size int, seed int64) rand.Source {
return &BufferedSource{
size: size,
src: rand.NewSource(1),
}
}
func (src *BufferedSource) Int63() int64 {
src.lk.Lock()
defer src.lk.Unlock()
if len(src.buffer) == 0 {
src.buffer = make([]int64, src.size)
for i := 0; i < src.size; i++ {
src.buffer[i] = src.src.Int63()
}
}
val := src.buffer[0]
src.buffer = src.buffer[1:]
return val
}
func (src *BufferedSource) Seed(seed int64) {
panic("BufferedSource does not support seed")
}
// See http://vigna.di.unimi.it/ftp/papers/xorshift.pdf
type XorShift64Source struct {
state uint64
}
func (src *XorShift64Source) Seed(seed int64) {
src.state = uint64(seed)
}
func (src *XorShift64Source) Int63() int64 {
x := src.state
x ^= x >> 12 // a
x ^= x << 25 // b
x ^= x >> 27 // c
src.state = x
return int64((x * 2685821657736338717) >> 1)
}
func TestXorShift64(t *testing.T) {
source := XorShift64Source{1}
for i := 0; i < 999; i++ {
val := source.Int63()
require.True(t, val >= 0, "Source returned %d < 0", val)
}
}
func BenchmarkCreateUnlocked(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
rand.NewSource(1)
}
})
}
func BenchmarkReadFromUnlocked(b *testing.B) {
source := rand.NewSource(1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
source.Int63()
}
}
func BenchmarkReadFromXorShift64(b *testing.B) {
source := &XorShift64Source{1}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
func BenchmarkReadFromLocked(b *testing.B) {
source := NewLockedSource(1)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
func BenchmarkPool(b *testing.B) {
pool := sync.Pool{
New: func() interface{} {
return rand.NewSource(1)
},
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source := pool.Get().(rand.Source)
pool.Put(source)
}
})
}
func BenchmarkChanBuffered1(b *testing.B) {
source := NewChanBufferedSource(1, 1)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
func BenchmarkChanBuffered100(b *testing.B) {
source := NewChanBufferedSource(100, 1)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
func BenchmarkBuffered1(b *testing.B) {
source := NewBufferedSource(1, 1)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
func BenchmarkBuffered100(b *testing.B) {
source := NewBufferedSource(100, 1)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
source.Int63()
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment