Skip to content

Commit

Permalink
more faster rand
Browse files Browse the repository at this point in the history
  • Loading branch information
phuslu committed Mar 20, 2024
1 parent 6c1760a commit d1be85e
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 105 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ jobs:
- name: Throughput benchmarks
working-directory: ./bench
run: |
env writeratio=0.1 zipf=false go test -v -cpu=8 -run=none -bench=. -benchtime=5s -benchmem bench_test.go
env writeratio=0.01 zipf=true go test -v -cpu=8 -run=none -bench=. -benchtime=5s -benchmem bench_test.go
env writeratio=0.1 zipfian=false go test -v -cpu=8 -run=none -bench=. -benchtime=5s -benchmem bench_test.go
env writeratio=0.01 zipfian=true go test -v -cpu=8 -run=none -bench=. -benchtime=5s -benchmem bench_test.go
- name: Memory Usage
working-directory: ./bench
run: |
Expand Down
222 changes: 119 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ package bench
import (
"crypto/sha1"
"fmt"
"math/rand"
"math/rand/v2"
"math/bits"
"os"
"runtime"
"strconv"
Expand Down Expand Up @@ -98,12 +99,24 @@ var threshold = func() uint32 {
return uint32(float64(^uint32(0)) * writeratio)
}()

var zipfian = func() (zipf func() uint64) {
ok, _ := strconv.ParseBool(os.Getenv("zipf"))
if !ok {
return nil
}
return rand.NewZipf(rand.New(rand.NewSource(time.Now().UnixNano())), 1.0001, 10, cachesize-1).Uint64
var zipfian, _ = strconv.ParseBool(os.Getenv("zipfian"))

type CheapRand struct {
Seed uint64
}

func (rand *CheapRand) Uint32() uint32 {
rand.Seed += 0xa0761d6478bd642f
hi, lo := bits.Mul64(rand.Seed, rand.Seed^0xe7037ed1a0b428db)
return uint32(hi ^ lo)
}

func (rand *CheapRand) Uint32n(n uint32) uint32 {
return uint32((uint64(rand.Uint32()) * uint64(n)) >> 32)
}

func (rand *CheapRand) Uint64() uint64 {
return uint64(rand.Uint32())<<32 ^ uint64(rand.Uint32())
}

var shardcount = func() int {
Expand All @@ -123,14 +136,6 @@ var keys = func() (x []string) {
return
}()

//go:noescape
//go:linkname cheaprandn runtime.cheaprandn
func cheaprandn(x uint32) uint32

//go:noescape
//go:linkname cheaprand runtime.cheaprand
func cheaprand() uint32

func BenchmarkHashicorpSetGet(b *testing.B) {
c := perfbench.Open(b)
cache := hashicorp.NewLRU[string, int](cachesize, nil, time.Hour)
Expand All @@ -141,15 +146,16 @@ func BenchmarkHashicorpSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Add(keys[i], i)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -166,15 +172,16 @@ func BenchmarkCloudflareSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i, expires)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -190,15 +197,16 @@ func BenchmarkEcacheSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Put(keys[i], i)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -218,15 +226,16 @@ func BenchmarkLxzanSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -246,15 +255,16 @@ func BenchmarkFreelruSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.AddWithLifetime(keys[i], i, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -270,15 +280,16 @@ func BenchmarkPhusluSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -294,15 +305,16 @@ func BenchmarkNoTTLSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -318,15 +330,16 @@ func BenchmarkCcacheSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -346,15 +359,16 @@ func BenchmarkRistrettoSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.SetWithTTL(keys[i], i, 1, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -370,15 +384,16 @@ func BenchmarkTheineSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.SetWithTTL(keys[i], i, 1, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -394,15 +409,16 @@ func BenchmarkOtterSetGet(b *testing.B) {
b.ResetTimer()
c.Reset()
b.RunParallel(func(pb *testing.PB) {
zipf := zipfian()
cheaprand := &CheapRand{uint64(time.Now().UnixNano())}
zipf := rand.NewZipf(rand.New(cheaprand), 1.0001, 10, cachesize-1)
for pb.Next() {
if threshold > 0 && cheaprand() <= threshold {
i := int(cheaprandn(cachesize))
if threshold > 0 && cheaprand.Uint32() <= threshold {
i := int(cheaprand.Uint32n(cachesize))
cache.Set(keys[i], i, time.Hour)
} else if zipf == nil {
cache.Get(keys[cheaprandn(cachesize)])
} else if zipfian {
cache.Get(keys[zipf.Uint64()])
} else {
cache.Get(keys[zipf()])
cache.Get(keys[cheaprand.Uint32n(cachesize)])
}
}
})
Expand All @@ -416,27 +432,27 @@ goos: linux
goarch: amd64
cpu: AMD EPYC 7763 64-Core Processor
BenchmarkHashicorpSetGet
BenchmarkHashicorpSetGet-8 13189354 555.3 ns/op 11 B/op 0 allocs/op
BenchmarkHashicorpSetGet-8 12765088 561.0 ns/op 11 B/op 0 allocs/op
BenchmarkCloudflareSetGet
BenchmarkCloudflareSetGet-8 36978129 204.5 ns/op 16 B/op 1 allocs/op
BenchmarkCloudflareSetGet-8 35771688 205.1 ns/op 16 B/op 1 allocs/op
BenchmarkEcacheSetGet
BenchmarkEcacheSetGet-8 45151062 145.3 ns/op 2 B/op 0 allocs/op
BenchmarkEcacheSetGet-8 47090353 141.7 ns/op 2 B/op 0 allocs/op
BenchmarkLxzanSetGet
BenchmarkLxzanSetGet-8 46670901 155.4 ns/op 0 B/op 0 allocs/op
BenchmarkLxzanSetGet-8 47349949 155.6 ns/op 0 B/op 0 allocs/op
BenchmarkFreelruSetGet
BenchmarkFreelruSetGet-8 56836291 141.6 ns/op 0 B/op 0 allocs/op
BenchmarkFreelruSetGet-8 55025196 142.0 ns/op 0 B/op 0 allocs/op
BenchmarkPhusluSetGet
BenchmarkPhusluSetGet-8 62015964 112.1 ns/op 0 B/op 0 allocs/op
BenchmarkPhusluSetGet-8 65641137 115.5 ns/op 0 B/op 0 allocs/op
BenchmarkCcacheSetGet
BenchmarkCcacheSetGet-8 21438442 360.4 ns/op 34 B/op 2 allocs/op
BenchmarkCcacheSetGet-8 20785468 362.6 ns/op 34 B/op 2 allocs/op
BenchmarkRistrettoSetGet
BenchmarkRistrettoSetGet-8 34435500 148.9 ns/op 29 B/op 1 allocs/op
BenchmarkRistrettoSetGet-8 35364735 150.7 ns/op 28 B/op 1 allocs/op
BenchmarkTheineSetGet
BenchmarkTheineSetGet-8 22269817 302.5 ns/op 5 B/op 0 allocs/op
BenchmarkTheineSetGet-8 20037783 319.3 ns/op 5 B/op 0 allocs/op
BenchmarkOtterSetGet
BenchmarkOtterSetGet-8 52233636 157.0 ns/op 8 B/op 0 allocs/op
BenchmarkOtterSetGet-8 51740157 177.4 ns/op 8 B/op 0 allocs/op
PASS
ok command-line-arguments 104.021s
ok command-line-arguments 114.650s
```

with zipfian read (99%) and randomly write(1%)
Expand All @@ -445,27 +461,27 @@ goos: linux
goarch: amd64
cpu: AMD EPYC 7763 64-Core Processor
BenchmarkHashicorpSetGet
BenchmarkHashicorpSetGet-8 14609264 418.5 ns/op 0 B/op 0 allocs/op
BenchmarkHashicorpSetGet-8 12838653 396.6 ns/op 0 B/op 0 allocs/op
BenchmarkCloudflareSetGet
BenchmarkCloudflareSetGet-8 51900106 125.5 ns/op 16 B/op 1 allocs/op
BenchmarkCloudflareSetGet-8 51687014 123.8 ns/op 16 B/op 1 allocs/op
BenchmarkEcacheSetGet
BenchmarkEcacheSetGet-8 62488617 98.76 ns/op 0 B/op 0 allocs/op
BenchmarkEcacheSetGet-8 62595678 101.9 ns/op 0 B/op 0 allocs/op
BenchmarkLxzanSetGet
BenchmarkLxzanSetGet-8 65241264 96.99 ns/op 0 B/op 0 allocs/op
BenchmarkLxzanSetGet-8 63740108 103.1 ns/op 0 B/op 0 allocs/op
BenchmarkFreelruSetGet
BenchmarkFreelruSetGet-8 60159511 108.4 ns/op 0 B/op 0 allocs/op
BenchmarkFreelruSetGet-8 57967554 108.8 ns/op 0 B/op 0 allocs/op
BenchmarkPhusluSetGet
BenchmarkPhusluSetGet-8 81835609 78.86 ns/op 0 B/op 0 allocs/op
BenchmarkPhusluSetGet-8 79727785 77.63 ns/op 0 B/op 0 allocs/op
BenchmarkCcacheSetGet
BenchmarkCcacheSetGet-8 22419021 256.8 ns/op 21 B/op 2 allocs/op
BenchmarkCcacheSetGet-8 22384370 264.6 ns/op 21 B/op 2 allocs/op
BenchmarkRistrettoSetGet
BenchmarkRistrettoSetGet-8 53689315 112.1 ns/op 21 B/op 1 allocs/op
BenchmarkRistrettoSetGet-8 44779450 114.8 ns/op 20 B/op 1 allocs/op
BenchmarkTheineSetGet
BenchmarkTheineSetGet-8 36106326 175.1 ns/op 0 B/op 0 allocs/op
BenchmarkTheineSetGet-8 30659925 172.7 ns/op 0 B/op 0 allocs/op
BenchmarkOtterSetGet
BenchmarkOtterSetGet-8 78723906 80.51 ns/op 1 B/op 0 allocs/op
BenchmarkOtterSetGet-8 75220942 86.18 ns/op 1 B/op 0 allocs/op
PASS
ok command-line-arguments 96.150s
ok command-line-arguments 96.119s
```

### Memory usage
Expand Down

0 comments on commit d1be85e

Please sign in to comment.