dcrd/container/apbf/bench_test.go
Dave Collins 395336affc
apbf: Add benchmarks.
This adds benchmarks for various APBF methods including the primary APBF
filter operations of Add and Contains for both the worst case when an
item matches the filter as well as the average case when an item does
NOT match the filter.

The following shows the results on a Ryzen 7 1700 processor:

capacity=1000, fprate=0.1%
--------------------------
BenchmarkAdd             7759802    155.0 ns/op   0 B/op   0 allocs/op
BenchmarkContainsTrue	 6865903    175.6 ns/op   0 B/op   0 allocs/op
BenchmarkContainsFalse   25966916   45.29 ns/op   0 B/op   0 allocs/op
BenchmarkReset           1020956    117.0 ns/op   0 B/op   0 allocs/op

capacity=1000, fprate=0.01%
---------------------------
BenchmarkAdd             5748116    207.3 ns/op	  0 B/op   0 allocs/op
BenchmarkContainsTrue    5351280    229.6 ns/op	  0 B/op   0 allocs/op
BenchmarkContainsFalse   24985996   45.29 ns/op   0 B/op   0 allocs/op
BenchmarkReset           8158309    145.0 ns/op	  0 B/op   0 allocs/op

capacity=1000, fprate=0.001%
----------------------------
BenchmarkAdd             4868738    244.8 ns/op	  0 B/op   0 allocs/op
BenchmarkContainsTrue    4579454    270.8 ns/op   0 B/op   0 allocs/op
BenchmarkContainsFalse   26251509   45.48 ns/op	  0 B/op   0 allocs/op
BenchmarkReset           6912676    175.1 ns/op	  0 B/op   0 allocs/op

capacity=10000, fprate=0.001%
-----------------------------
BenchmarkReset           749980     1625 ns/op    0 B/op   0 allocs/op

capacity=100000, fprate=0.01%
-----------------------------
BenchmarkAdd             6168745    203.1 ns/op   0 B/op   0 allocs/op
BenchmarkContainsTrue    5849455    210.5 ns/op   0 B/op   0 allocs/op
BenchmarkContainsFalse   26782545   44.06 ns/op   0 B/op   0 allocs/op

capacity=100000, fprate=0.0001%
-------------------------------
BenchmarkAdd             4348394    265.8 ns/op   0 B/op   0 allocs/op
BenchmarkContainsTrue    4236044    282.3 ns/op   0 B/op   0 allocs/op
BenchmarkContainsFalse   27291583   44.61 ns/op   0 B/op   0 allocs/op
BenchmarkReset           67348      17542 ns/op   0 B/op   0 allocs/op

capacity=100000, fprate=0.00001%
--------------------------------
BenchmarkAdd             2702445    462.8 ns/op   0 B/op   0 allocs/op
2021-02-03 23:11:10 -06:00

228 lines
5.1 KiB
Go

// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package apbf
import (
"encoding/binary"
"fmt"
"testing"
)
// BenchmarkAdd benchmarks adding items to an APBF for various capacities and
// false positive rates.
func BenchmarkAdd(b *testing.B) {
benches := []struct {
capacity uint32 // target capacity
fpRate float64 // target false positive rate
}{{
capacity: 1000,
fpRate: 0.001,
}, {
capacity: 1000,
fpRate: 0.0001,
}, {
capacity: 1000,
fpRate: 0.00001,
}, {
capacity: 100000,
fpRate: 0.0001,
}, {
capacity: 100000,
fpRate: 0.000001,
}, {
capacity: 1000000,
fpRate: 0.0000001,
}}
for benchIdx := range benches {
bench := benches[benchIdx]
benchName := fmt.Sprintf("capacity=%d/fprate=%0.7f", bench.capacity,
bench.fpRate)
b.Run(benchName, func(b *testing.B) {
filter := NewFilter(bench.capacity, bench.fpRate)
b.ResetTimer()
b.ReportAllocs()
var data [4]byte
for i := 0; i < b.N; i++ {
binary.LittleEndian.PutUint32(data[:], uint32(i))
filter.Add(data[:])
}
})
}
}
// BenchmarkContainsTrue benchmarks membership queries on an APBF for various
// capacities and false positive rates when the item exists in the filter and
// is near worst case performance.
func BenchmarkContainsTrue(b *testing.B) {
benches := []struct {
capacity uint32 // target capacity
fpRate float64 // target false positive rate
}{{
capacity: 1000,
fpRate: 0.001,
}, {
capacity: 1000,
fpRate: 0.0001,
}, {
capacity: 1000,
fpRate: 0.00001,
}, {
capacity: 100000,
fpRate: 0.0001,
}, {
capacity: 100000,
fpRate: 0.000001,
}}
for benchIdx := range benches {
bench := benches[benchIdx]
benchName := fmt.Sprintf("capacity=%d/fprate=%0.6f", bench.capacity,
bench.fpRate)
b.Run(benchName, func(b *testing.B) {
// Load the filter so the benchmark is with a max capacity filter.
filter := NewFilter(bench.capacity, bench.fpRate)
var data [4]byte
for i := uint32(0); i < filter.Capacity(); i++ {
binary.LittleEndian.PutUint32(data[:], i)
filter.Add(data[:])
}
binary.LittleEndian.PutUint32(data[:], filter.Capacity()/2)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
filter.Contains(data[:])
}
})
}
}
// BenchmarkContainsFalse benchmarks membership queries on an APBF for various
// capacities and false positive rates when the item does not exist in the
// filter.
func BenchmarkContainsFalse(b *testing.B) {
benches := []struct {
capacity uint32 // target capacity
fpRate float64 // target false positive rate
}{{
capacity: 1000,
fpRate: 0.001,
}, {
capacity: 1000,
fpRate: 0.0001,
}, {
capacity: 1000,
fpRate: 0.00001,
}, {
capacity: 100000,
fpRate: 0.0001,
}, {
capacity: 100000,
fpRate: 0.000001,
}}
for benchIdx := range benches {
bench := benches[benchIdx]
benchName := fmt.Sprintf("capacity=%d/fprate=%0.6f", bench.capacity,
bench.fpRate)
b.Run(benchName, func(b *testing.B) {
// Load the filter so the benchmark is with a max capacity filter.
filter := NewFilter(bench.capacity, bench.fpRate)
var data [4]byte
for i := uint32(0); i < filter.Capacity(); i++ {
binary.LittleEndian.PutUint32(data[:], i)
filter.Add(data[:])
}
binary.LittleEndian.PutUint32(data[:], filter.Capacity()+1)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
filter.Contains(data[:])
}
})
}
}
// BenchmarkReset benchmarks resetting an APBF for various capacities and false
// positive rates.
func BenchmarkReset(b *testing.B) {
benches := []struct {
capacity uint32 // target capacity
fpRate float64 // target false positive rate
}{{
capacity: 1000,
fpRate: 0.001,
}, {
capacity: 1000,
fpRate: 0.0001,
}, {
capacity: 1000,
fpRate: 0.00001,
}, {
capacity: 10000,
fpRate: 0.00001,
}, {
capacity: 100000,
fpRate: 0.000001,
}}
for benchIdx := range benches {
bench := benches[benchIdx]
benchName := fmt.Sprintf("capacity=%d/fprate=%0.6f", bench.capacity,
bench.fpRate)
b.Run(benchName, func(b *testing.B) {
filter := NewFilter(bench.capacity, bench.fpRate)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
filter.Reset()
}
})
}
}
// BenchmarkNewFilter benchmarks creating a new APBF for various capacities and
// false positive rates.
func BenchmarkNewFilter(b *testing.B) {
benches := []struct {
capacity uint32 // target capacity
fpRate float64 // target false positive rate
}{{
capacity: 1000,
fpRate: 0.001,
}, {
capacity: 1000,
fpRate: 0.0001,
}, {
capacity: 1000,
fpRate: 0.00001,
}, {
capacity: 10000,
fpRate: 0.00001,
}, {
capacity: 100000,
fpRate: 0.000001,
}}
var noElide *Filter
for benchIdx := range benches {
bench := benches[benchIdx]
benchName := fmt.Sprintf("capacity=%d/fprate=%0.6f", bench.capacity,
bench.fpRate)
b.Run(benchName, func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
noElide = NewFilter(bench.capacity, bench.fpRate)
}
})
}
_ = noElide
}