2019-09-24 18:10:22 +00:00
|
|
|
package uint64set
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/valyala/fastrand"
|
|
|
|
)
|
|
|
|
|
2020-07-21 17:56:49 +00:00
|
|
|
func BenchmarkAddMulti(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
a := sa.AppendTo(nil)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkAddMulti(b, a)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkAdd(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
a := sa.AppendTo(nil)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkAdd(b, a)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-18 11:39:50 +00:00
|
|
|
func BenchmarkUnionNoOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start+uint64(itemsCount), itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkUnion(b, sa, sb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkUnionPartialOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start+uint64(itemsCount/2), itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkUnion(b, sa, sb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkUnionFullOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start, itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkUnion(b, sa, sb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-21 17:56:49 +00:00
|
|
|
func benchmarkAdd(b *testing.B, a []uint64) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(len(a)))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
var s Set
|
|
|
|
for _, x := range a {
|
|
|
|
s.Add(x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmarkAddMulti(b *testing.B, a []uint64) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(len(a)))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
var s Set
|
|
|
|
n := 0
|
|
|
|
for n < len(a) {
|
|
|
|
m := n + 64
|
|
|
|
if m > len(a) {
|
|
|
|
m = len(a)
|
|
|
|
}
|
|
|
|
s.AddMulti(a[n:m])
|
|
|
|
n = m
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-01-18 11:39:50 +00:00
|
|
|
func benchmarkUnion(b *testing.B, sa, sb *Set) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(sa.Len() + sb.Len()))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
saCopy := sa.Clone()
|
|
|
|
sbCopy := sb.Clone()
|
|
|
|
saCopy.Union(sb)
|
|
|
|
sbCopy.Union(sa)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-01-17 14:07:49 +00:00
|
|
|
func BenchmarkIntersectNoOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start+uint64(itemsCount), itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkIntersect(b, sa, sb)
|
2020-01-16 21:29:03 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-17 14:07:49 +00:00
|
|
|
func BenchmarkIntersectPartialOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start+uint64(itemsCount/2), itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkIntersect(b, sa, sb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkIntersectFullOverlap(b *testing.B) {
|
|
|
|
for _, itemsCount := range []int{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
sa := createRangeSet(start, itemsCount)
|
|
|
|
sb := createRangeSet(start, itemsCount)
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
benchmarkIntersect(b, sa, sb)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmarkIntersect(b *testing.B, sa, sb *Set) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(sa.Len() + sb.Len()))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
saCopy := sa.Clone()
|
|
|
|
sbCopy := sb.Clone()
|
|
|
|
saCopy.Intersect(sb)
|
|
|
|
sbCopy.Intersect(sa)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func createRangeSet(start uint64, itemsCount int) *Set {
|
2020-01-16 21:29:03 +00:00
|
|
|
var s Set
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
2020-01-17 14:07:49 +00:00
|
|
|
n := start + uint64(i)
|
2020-01-16 21:29:03 +00:00
|
|
|
s.Add(n)
|
|
|
|
}
|
|
|
|
return &s
|
|
|
|
}
|
|
|
|
|
2019-09-24 18:10:22 +00:00
|
|
|
func BenchmarkSetAddRandomLastBits(b *testing.B) {
|
|
|
|
const itemsCount = 1e5
|
|
|
|
for _, lastBits := range []uint64{20, 24, 28, 32} {
|
|
|
|
mask := (uint64(1) << lastBits) - 1
|
|
|
|
b.Run(fmt.Sprintf("lastBits_%d", lastBits), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
2020-01-16 21:29:03 +00:00
|
|
|
var rng fastrand.RNG
|
2019-09-24 18:10:22 +00:00
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
var s Set
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
|
|
n := start | (uint64(rng.Uint32()) & mask)
|
|
|
|
s.Add(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapAddRandomLastBits(b *testing.B) {
|
|
|
|
const itemsCount = 1e5
|
|
|
|
for _, lastBits := range []uint64{20, 24, 28, 32} {
|
|
|
|
mask := (uint64(1) << lastBits) - 1
|
|
|
|
b.Run(fmt.Sprintf("lastBits_%d", lastBits), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
2020-01-16 21:29:03 +00:00
|
|
|
var rng fastrand.RNG
|
2019-09-24 18:10:22 +00:00
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
m := make(map[uint64]struct{})
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
|
|
n := start | (uint64(rng.Uint32()) & mask)
|
|
|
|
m[n] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSetAddWithAllocs(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
var s Set
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
s.Add(n)
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapAddWithAllocs(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
m := make(map[uint64]struct{})
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
m[n] = struct{}{}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapAddNoAllocs(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
m := make(map[uint64]struct{}, itemsCount)
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
m[n] = struct{}{}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapAddReuse(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
m := make(map[uint64]struct{}, itemsCount)
|
|
|
|
for pb.Next() {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
for k := range m {
|
|
|
|
delete(m, k)
|
|
|
|
}
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
m[n] = struct{}{}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSetHasHitRandomLastBits(b *testing.B) {
|
|
|
|
const itemsCount = 1e5
|
|
|
|
for _, lastBits := range []uint64{20, 24, 28, 32} {
|
2020-01-17 14:07:49 +00:00
|
|
|
mask := (uint64(1) << lastBits) - 1
|
2019-09-24 18:10:22 +00:00
|
|
|
b.Run(fmt.Sprintf("lastBits_%d", lastBits), func(b *testing.B) {
|
2020-01-17 14:07:49 +00:00
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
var s Set
|
|
|
|
var rng fastrand.RNG
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
|
|
n := start | (uint64(rng.Uint32()) & mask)
|
|
|
|
s.Add(n)
|
|
|
|
}
|
2019-09-24 18:10:22 +00:00
|
|
|
a := s.AppendTo(nil)
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(len(a)))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
for _, n := range a {
|
|
|
|
if !s.Has(n) {
|
|
|
|
panic("unexpected miss")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapHasHitRandomLastBits(b *testing.B) {
|
|
|
|
const itemsCount = 1e5
|
|
|
|
for _, lastBits := range []uint64{20, 24, 28, 32} {
|
|
|
|
mask := (uint64(1) << lastBits) - 1
|
|
|
|
b.Run(fmt.Sprintf("lastBits_%d", lastBits), func(b *testing.B) {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
m := make(map[uint64]struct{})
|
|
|
|
var rng fastrand.RNG
|
|
|
|
for i := 0; i < itemsCount; i++ {
|
|
|
|
n := start | (uint64(rng.Uint32()) & mask)
|
|
|
|
m[n] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(len(m)))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
for n := range m {
|
|
|
|
if _, ok := m[n]; !ok {
|
|
|
|
panic("unexpected miss")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSetHasHit(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
var s Set
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
s.Add(n)
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
if !s.Has(n) {
|
|
|
|
panic("unexpected miss")
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapHasHit(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
m := make(map[uint64]struct{}, itemsCount)
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
m[n] = struct{}{}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
if _, ok := m[n]; !ok {
|
|
|
|
panic("unexpected miss")
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkSetHasMiss(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
var s Set
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
s.Add(n)
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
n := end
|
|
|
|
nEnd := end + itemsCount
|
|
|
|
for n < nEnd {
|
|
|
|
if s.Has(n) {
|
|
|
|
panic("unexpected hit")
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMapHasMiss(b *testing.B) {
|
|
|
|
for _, itemsCount := range []uint64{1e3, 1e4, 1e5, 1e6, 1e7} {
|
|
|
|
b.Run(fmt.Sprintf("items_%d", itemsCount), func(b *testing.B) {
|
|
|
|
start := uint64(time.Now().UnixNano())
|
|
|
|
end := start + itemsCount
|
|
|
|
m := make(map[uint64]struct{}, itemsCount)
|
|
|
|
n := start
|
|
|
|
for n < end {
|
|
|
|
m[n] = struct{}{}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(int64(itemsCount))
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
for pb.Next() {
|
|
|
|
n := end
|
|
|
|
nEnd := end + itemsCount
|
|
|
|
for n < nEnd {
|
|
|
|
if _, ok := m[n]; ok {
|
|
|
|
panic("unexpected hit")
|
|
|
|
}
|
|
|
|
n++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|