1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
// Copyright 2020 the Blobloom authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package benchmarks contains benchmarks for various Bloom filter
// implementations, selected by build tags. See README.md for details.
package benchmarks
import (
"math/rand"
"testing"
)
const hashSize = 32
func makehashes(n int, seed int64) []byte {
h := make([]byte, n*hashSize)
r := rand.New(rand.NewSource(seed))
r.Read(h)
return h
}
// In each iteration, add a SHA-256 into a Bloom filter with the given capacity
// and desired FPR.
func benchmarkAdd(b *testing.B, capacity int, fpr float64) {
b.Helper()
hashes := makehashes(b.N, 51251991517)
f := newBF(capacity, fpr)
b.ResetTimer()
for i := 0; i < b.N; i++ {
h := hashes[i*hashSize : (i+1)*hashSize]
f.Add(h)
}
}
func BenchmarkAdd1e5_1e2(b *testing.B) { benchmarkAdd(b, 1e5, 1e-2) }
func BenchmarkAdd1e6_1e2(b *testing.B) { benchmarkAdd(b, 1e6, 1e-2) }
func BenchmarkAdd1e7_1e2(b *testing.B) { benchmarkAdd(b, 1e7, 1e-2) }
func BenchmarkAdd1e8_1e2(b *testing.B) { benchmarkAdd(b, 1e8, 1e-2) }
func BenchmarkAdd1e5_1e3(b *testing.B) { benchmarkAdd(b, 1e5, 1e-3) }
func BenchmarkAdd1e6_1e3(b *testing.B) { benchmarkAdd(b, 1e6, 1e-3) }
func BenchmarkAdd1e7_1e3(b *testing.B) { benchmarkAdd(b, 1e7, 1e-3) }
func BenchmarkAdd1e8_1e3(b *testing.B) { benchmarkAdd(b, 1e8, 1e-3) }
// In each iteration, test for a SHA-256 in a Bloom filter with the given capacity
// and desired FPR that has that SHA-256 added to it.
func benchmarkTestPos(b *testing.B, capacity int, fpr float64) {
b.Helper()
const ntest = 8192
hashes := makehashes(ntest, 0x5128351a)
f := newBF(capacity, fpr)
for i := 0; i < capacity && i < ntest; i++ {
h := hashes[i*hashSize : (i+1)*hashSize]
f.Add(h)
}
for i := ntest; i < capacity; i++ {
h := make([]byte, hashSize)
f.Add(h)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
j := i % ntest
h := hashes[j*hashSize : (j+1)*hashSize]
if !f.Has(h) {
b.Fatalf("%x added to Bloom filter but not retrieved", h)
}
}
}
func BenchmarkTestPos1e5_1e2(b *testing.B) { benchmarkTestPos(b, 1e5, 1e-2) }
func BenchmarkTestPos1e6_1e2(b *testing.B) { benchmarkTestPos(b, 1e6, 1e-2) }
func BenchmarkTestPos1e7_1e2(b *testing.B) { benchmarkTestPos(b, 1e7, 1e-2) }
func BenchmarkTestPos1e8_1e2(b *testing.B) { benchmarkTestPos(b, 1e8, 1e-2) }
func BenchmarkTestPos1e5_1e3(b *testing.B) { benchmarkTestPos(b, 1e5, 1e-3) }
func BenchmarkTestPos1e6_1e3(b *testing.B) { benchmarkTestPos(b, 1e6, 1e-3) }
func BenchmarkTestPos1e7_1e3(b *testing.B) { benchmarkTestPos(b, 1e7, 1e-3) }
func BenchmarkTestPos1e8_1e3(b *testing.B) { benchmarkTestPos(b, 1e8, 1e-3) }
// In each iteration, test for the presence of a SHA-256 in a filled Bloom filter
// with the given capacity and desired FPR.
func benchmarkTestNeg(b *testing.B, capacity int, fpr float64) {
b.Helper()
r := rand.New(rand.NewSource(0xae694))
f := newBF(capacity, fpr)
h := make([]byte, hashSize)
for i := 0; i < capacity; i++ {
r.Read(h)
f.Add(h)
}
// Make new hashes. Assume these are all distinct from the inserted ones.
const ntest = 8192
hashes := makehashes(ntest, 562175)
b.ResetTimer()
fp := 0
for i := 0; i < b.N; i++ {
j := i % ntest
h := hashes[j*hashSize : (j+1)*hashSize]
if f.Has(h) {
fp++
}
}
b.Logf("false positive rate = %.3f%%", 100*float64(fp)/float64(b.N))
}
func BenchmarkTestNeg1e5_1e2(b *testing.B) { benchmarkTestNeg(b, 1e5, 1e-2) }
func BenchmarkTestNeg1e6_1e2(b *testing.B) { benchmarkTestNeg(b, 1e6, 1e-2) }
func BenchmarkTestNeg1e7_1e2(b *testing.B) { benchmarkTestNeg(b, 1e7, 1e-2) }
func BenchmarkTestNeg1e8_1e2(b *testing.B) { benchmarkTestNeg(b, 1e8, 1e-2) }
func BenchmarkTestNeg1e5_1e3(b *testing.B) { benchmarkTestNeg(b, 1e5, 1e-3) }
func BenchmarkTestNeg1e6_1e3(b *testing.B) { benchmarkTestNeg(b, 1e6, 1e-3) }
func BenchmarkTestNeg1e7_1e3(b *testing.B) { benchmarkTestNeg(b, 1e7, 1e-3) }
func BenchmarkTestNeg1e8_1e3(b *testing.B) { benchmarkTestNeg(b, 1e8, 1e-3) }
// In each iteration, test for the presence of a SHA-256 in an empty Bloom filter
// with the given capacity and desired FPR.
func benchmarkTestEmpty(b *testing.B, capacity int, fpr float64) {
b.Helper()
const ntest = 65536
hashes := makehashes(ntest, 054271)
f := newBF(capacity, fpr)
b.ResetTimer()
for i := 0; i < b.N; i++ {
j := i % ntest
f.Has(hashes[j*hashSize : (j+1)*hashSize])
}
}
func BenchmarkTestEmpty1e5_1e2(b *testing.B) { benchmarkTestEmpty(b, 1e5, 1e-2) }
func BenchmarkTestEmpty1e6_1e2(b *testing.B) { benchmarkTestEmpty(b, 1e6, 1e-2) }
func BenchmarkTestEmpty1e7_1e2(b *testing.B) { benchmarkTestEmpty(b, 1e7, 1e-2) }
func BenchmarkTestEmpty1e8_1e2(b *testing.B) { benchmarkTestEmpty(b, 1e8, 1e-2) }
func BenchmarkTestEmpty1e5_1e3(b *testing.B) { benchmarkTestEmpty(b, 1e5, 1e-3) }
func BenchmarkTestEmpty1e6_1e3(b *testing.B) { benchmarkTestEmpty(b, 1e6, 1e-3) }
func BenchmarkTestEmpty1e7_1e3(b *testing.B) { benchmarkTestEmpty(b, 1e7, 1e-3) }
func BenchmarkTestEmpty1e8_1e3(b *testing.B) { benchmarkTestEmpty(b, 1e8, 1e-3) }
|