Perf: avoid using rand.Rand casting
This commit is contained in:
parent
19fdd70713
commit
4b9164bd75
@ -4,8 +4,11 @@ import (
|
|||||||
crip "crypto/rand"
|
crip "crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"nullprogram.com/x/rng"
|
"nullprogram.com/x/rng"
|
||||||
|
|
||||||
@ -16,11 +19,11 @@ type randPool struct {
|
|||||||
sync.Pool
|
sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *randPool) Get() *rand.Rand {
|
func (p *randPool) Get() *rng.SplitMix64 {
|
||||||
return p.Pool.Get().(*rand.Rand)
|
return p.Pool.Get().(*rng.SplitMix64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *randPool) Put(r *rand.Rand) {
|
func (p *randPool) Put(r *rng.SplitMix64) {
|
||||||
p.Pool.Put(r)
|
p.Pool.Put(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,8 +33,7 @@ var (
|
|||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
sm64 := new(rng.SplitMix64)
|
sm64 := new(rng.SplitMix64)
|
||||||
sm64.Seed(GetCryptoSeed())
|
sm64.Seed(GetCryptoSeed())
|
||||||
prng := rand.New(sm64) //nolint:gosec
|
return sm64
|
||||||
return prng
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -42,16 +44,18 @@ var (
|
|||||||
|
|
||||||
func setSharedRand() {
|
func setSharedRand() {
|
||||||
hardLocc.Lock()
|
hardLocc.Lock()
|
||||||
sharedRand = lolXD.Get()
|
sharedRand = rand.New(lolXD.Get())
|
||||||
hardLocc.Unlock()
|
hardLocc.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func AcquireRand() *rand.Rand {
|
func AcquireRand() *rand.Rand {
|
||||||
return lolXD.Get()
|
return rand.New(lolXD.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReleaseRand(r *rand.Rand) {
|
func ReleaseRand(r *rand.Rand) {
|
||||||
lolXD.Put(r)
|
srcField := reflect.ValueOf(r).Elem().FieldByName("src")
|
||||||
|
src := reflect.NewAt(srcField.Type(), unsafe.Pointer(srcField.UnsafeAddr())).Elem().Interface().(*rng.SplitMix64)
|
||||||
|
lolXD.Put(src)
|
||||||
r = nil
|
r = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,18 +84,17 @@ func GetOptimizedRand() *rand.Rand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetSharedRand returns a pointer to our shared optimized rand.Rand which uses crypto/rand to seed a splitmix64 rng.
|
// GetSharedRand returns a pointer to our shared optimized rand.Rand which uses crypto/rand to seed a splitmix64 rng.
|
||||||
// WARNING - RACY - This is not thread safe, and should only be used in a single-threaded context.
|
|
||||||
func GetSharedRand() *rand.Rand {
|
func GetSharedRand() *rand.Rand {
|
||||||
getSharedRand.Do(func() {
|
getSharedRand.Do(func() {
|
||||||
setSharedRand()
|
setSharedRand()
|
||||||
})
|
})
|
||||||
return sharedRand
|
return rand.New(sharedRand)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RNGUint32 returns a random uint32 using crypto/rand and splitmix64.
|
// RNGUint32 returns a random uint32 using crypto/rand and splitmix64.
|
||||||
func RNGUint32() uint32 {
|
func RNGUint32() uint32 {
|
||||||
r := lolXD.Get()
|
r := lolXD.Get()
|
||||||
ui := r.Uint32()
|
ui := uint32(r.Int63() >> 31)
|
||||||
lolXD.Put(r)
|
lolXD.Put(r)
|
||||||
return ui
|
return ui
|
||||||
}
|
}
|
||||||
@ -106,8 +109,25 @@ RNG returns integer with a maximum amount of 'n' using a global/shared instance
|
|||||||
*/
|
*/
|
||||||
func RNG(n int) int {
|
func RNG(n int) int {
|
||||||
r := lolXD.Get()
|
r := lolXD.Get()
|
||||||
i := r.Intn(n)
|
defer lolXD.Put(r)
|
||||||
lolXD.Put(r)
|
i := 0
|
||||||
|
if n <= 0 {
|
||||||
|
// because panic is just rude.
|
||||||
|
_, _ = os.Stderr.WriteString("RNG: n must be greater than 0, returning 0")
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
if n <= 1<<31-1 {
|
||||||
|
n32 := int32(n)
|
||||||
|
if n32&(n32-1) == 0 {
|
||||||
|
i = int(int32(r.Int63()>>32) & (n32 - 1))
|
||||||
|
}
|
||||||
|
maximum := int32((1 << 31) - 1 - (1<<31)%uint32(n32))
|
||||||
|
v := int32(r.Int63() >> 32)
|
||||||
|
for v > maximum {
|
||||||
|
v = int32(r.Int63() >> 32)
|
||||||
|
}
|
||||||
|
i = int(v % n32)
|
||||||
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +187,7 @@ func randStr(upper bool, size int) string {
|
|||||||
buf := strBufs.Get()
|
buf := strBufs.Get()
|
||||||
r := lolXD.Get()
|
r := lolXD.Get()
|
||||||
for i := 0; i != size; i++ {
|
for i := 0; i != size; i++ {
|
||||||
ui32 := int(r.Uint32())
|
ui32 := int(r.Int63() >> 31)
|
||||||
switch upper {
|
switch upper {
|
||||||
case true:
|
case true:
|
||||||
_ = buf.WriteByte(charsetWithUpper[ui32%len(charsetWithUpper)])
|
_ = buf.WriteByte(charsetWithUpper[ui32%len(charsetWithUpper)])
|
||||||
|
@ -49,15 +49,15 @@ func Test_RNG(t *testing.T) {
|
|||||||
t.Errorf("GetSharedRand(55555) returned the same value twice!")
|
t.Errorf("GetSharedRand(55555) returned the same value twice!")
|
||||||
}
|
}
|
||||||
r := AcquireRand()
|
r := AcquireRand()
|
||||||
one := r.Intn(55555)
|
one := r.Uint64()
|
||||||
two := r.Intn(55555)
|
two := r.Uint64()
|
||||||
if one == two {
|
if one == two {
|
||||||
t.Errorf("AcquireRand() returned the same value twice!")
|
t.Errorf("AcquireRand() returned the same value twice!")
|
||||||
}
|
}
|
||||||
ReleaseRand(r)
|
ReleaseRand(r)
|
||||||
r = AcquireRand()
|
r = AcquireRand()
|
||||||
one1 := r.Intn(55555)
|
one1 := r.Uint64()
|
||||||
two1 := r.Intn(55555)
|
two1 := r.Uint64()
|
||||||
if one1 == two1 {
|
if one1 == two1 {
|
||||||
t.Errorf("AcquireRand() returned the same value twice!")
|
t.Errorf("AcquireRand() returned the same value twice!")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user