mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
improve union-related benchmarking
Add a benchmark to test a specific case where UnionInPlace is underperforming the naive union operation badly. Also, the UnionBulk test was reusing a bitmap, meaning that it ended up doing a lot of unions into a bitmap that already had all the bits it was supposed to have. This broke a couple of other tests in unexpected ways. We also now use UnionInPlace in importRoaring, and test it in the container combinations tests via a wrapper.
This commit is contained in:
parent
a28141c466
commit
054cb206d5
3 changed files with 177 additions and 9 deletions
|
|
@ -1763,8 +1763,11 @@ func (f *fragment) importRoaring(data []byte, clear bool) error {
|
|||
|
||||
if clear {
|
||||
bm = f.storage.Difference(bm)
|
||||
} else if f.storage.Any() {
|
||||
bm = f.storage.Union(bm)
|
||||
} else if f.storage.Containers.Size() >= bm.Containers.Size() {
|
||||
f.storage.UnionInPlace(bm)
|
||||
bm = f.storage
|
||||
} else {
|
||||
bm.UnionInPlace(f.storage)
|
||||
}
|
||||
|
||||
for rowID := range rowSet {
|
||||
|
|
|
|||
|
|
@ -2699,6 +2699,18 @@ func getFunctionName(i interface{}) string {
|
|||
return y[0]
|
||||
}
|
||||
|
||||
// UnionInPlace is defined at the Bitmap level, but this wrapper lets us insert
|
||||
// it into our ContainerCombinations tests so that it gets exercised on a wide
|
||||
// variety of container data.
|
||||
func unionInPlaceWrapper(a, b *Container) *Container {
|
||||
out := NewBitmap()
|
||||
out.Containers.Put(0, a.Clone())
|
||||
B := NewBitmap()
|
||||
B.Containers.Put(0, b)
|
||||
out.UnionInPlace(B)
|
||||
return out.Containers.Get(0)
|
||||
}
|
||||
|
||||
func TestContainerCombinations(t *testing.T) {
|
||||
|
||||
cts := setupContainerTests()
|
||||
|
|
@ -2935,6 +2947,117 @@ func TestContainerCombinations(t *testing.T) {
|
|||
{union, "evenBitsSet", "oddBitsSet", "full"},
|
||||
{union, "evenBitsSet", "evenBitsSet", "evenBitsSet"},
|
||||
|
||||
// unionInPlaceWrapper
|
||||
{unionInPlaceWrapper, "empty", "empty", "empty"},
|
||||
{unionInPlaceWrapper, "empty", "full", "full"},
|
||||
{unionInPlaceWrapper, "empty", "firstBitSet", "firstBitSet"},
|
||||
{unionInPlaceWrapper, "empty", "lastBitSet", "lastBitSet"},
|
||||
{unionInPlaceWrapper, "empty", "firstBitUnset", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "empty", "lastBitUnset", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "empty", "innerBitsSet", "innerBitsSet"},
|
||||
{unionInPlaceWrapper, "empty", "outerBitsSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "empty", "oddBitsSet", "oddBitsSet"},
|
||||
{unionInPlaceWrapper, "empty", "evenBitsSet", "evenBitsSet"},
|
||||
//
|
||||
{unionInPlaceWrapper, "full", "empty", "full"},
|
||||
{unionInPlaceWrapper, "full", "full", "full"},
|
||||
{unionInPlaceWrapper, "full", "firstBitSet", "full"},
|
||||
{unionInPlaceWrapper, "full", "lastBitSet", "full"},
|
||||
{unionInPlaceWrapper, "full", "firstBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "full", "lastBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "full", "innerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "full", "outerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "full", "oddBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "full", "evenBitsSet", "full"},
|
||||
//
|
||||
{unionInPlaceWrapper, "firstBitSet", "empty", "firstBitSet"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "full", "full"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "firstBitSet", "firstBitSet"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "lastBitSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "firstBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "lastBitUnset", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "innerBitsSet", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitSet", "outerBitsSet", "outerBitsSet"},
|
||||
//{unionInPlaceWrapper, "firstBitSet", "oddBitsSet", ""},
|
||||
{unionInPlaceWrapper, "firstBitSet", "evenBitsSet", "evenBitsSet"},
|
||||
//
|
||||
{unionInPlaceWrapper, "lastBitSet", "empty", "lastBitSet"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "full", "full"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "firstBitSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "lastBitSet", "lastBitSet"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "firstBitUnset", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "lastBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "innerBitsSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "outerBitsSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "lastBitSet", "oddBitsSet", "oddBitsSet"},
|
||||
//{unionInPlaceWrapper, "lastBitSet", "evenBitsSet", ""},
|
||||
//
|
||||
{unionInPlaceWrapper, "firstBitUnset", "empty", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "full", "full"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "firstBitSet", "full"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "lastBitSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "firstBitUnset", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "lastBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "innerBitsSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "outerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "oddBitsSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "firstBitUnset", "evenBitsSet", "full"},
|
||||
//
|
||||
{unionInPlaceWrapper, "lastBitUnset", "empty", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "full", "full"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "firstBitSet", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "lastBitSet", "full"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "firstBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "lastBitUnset", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "innerBitsSet", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "outerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "oddBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "lastBitUnset", "evenBitsSet", "lastBitUnset"},
|
||||
//
|
||||
{unionInPlaceWrapper, "innerBitsSet", "empty", "innerBitsSet"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "full", "full"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "firstBitSet", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "lastBitSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "firstBitUnset", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "lastBitUnset", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "innerBitsSet", "innerBitsSet"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "outerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "oddBitsSet", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "innerBitsSet", "evenBitsSet", "lastBitUnset"},
|
||||
//
|
||||
{unionInPlaceWrapper, "outerBitsSet", "empty", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "full", "full"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "firstBitSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "lastBitSet", "outerBitsSet"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "firstBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "lastBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "innerBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "outerBitsSet", "outerBitsSet", "outerBitsSet"},
|
||||
//{unionInPlaceWrapper, "outerBitsSet", "oddBitsSet", ""},
|
||||
//{unionInPlaceWrapper, "outerBitsSet", "evenBitsSet", ""},
|
||||
//
|
||||
{unionInPlaceWrapper, "oddBitsSet", "empty", "oddBitsSet"},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "full", "full"},
|
||||
//{unionInPlaceWrapper, "oddBitsSet", "firstBitSet", ""},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "lastBitSet", "oddBitsSet"},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "firstBitUnset", "firstBitUnset"},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "lastBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "innerBitsSet", "firstBitUnset"},
|
||||
//{unionInPlaceWrapper, "oddBitsSet", "outerBitsSet", ""},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "oddBitsSet", "oddBitsSet"},
|
||||
{unionInPlaceWrapper, "oddBitsSet", "evenBitsSet", "full"},
|
||||
//
|
||||
{unionInPlaceWrapper, "evenBitsSet", "empty", "evenBitsSet"},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "full", "full"},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "firstBitSet", "evenBitsSet"},
|
||||
//{unionInPlaceWrapper, "evenBitsSet", "lastBitSet", ""},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "firstBitUnset", "full"},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "lastBitUnset", "lastBitUnset"},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "innerBitsSet", "lastBitUnset"},
|
||||
//{unionInPlaceWrapper, "evenBitsSet", "outerBitsSet", ""},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "oddBitsSet", "full"},
|
||||
{unionInPlaceWrapper, "evenBitsSet", "evenBitsSet", "evenBitsSet"},
|
||||
|
||||
// difference
|
||||
{difference, "empty", "empty", "empty"},
|
||||
{difference, "empty", "full", "empty"},
|
||||
|
|
@ -3653,3 +3776,45 @@ func TestDirectAddNVsAdd(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkUnionInPlaceRegression(b *testing.B) {
|
||||
initial := make([]uint64, 0, 10100)
|
||||
a1 := make([]uint64, 0, 10000)
|
||||
a2 := make([]uint64, 0, 10000)
|
||||
for i := uint64(0); i < 1<<30; i += 100000 {
|
||||
initial = append(initial, i)
|
||||
a1 = append(a1, i+67000)
|
||||
a2 = append(a2, i/2)
|
||||
}
|
||||
a1BM := NewBTreeBitmap(a1...)
|
||||
a2BM := NewBTreeBitmap(a2...)
|
||||
b.Run("Union1", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bm := NewBTreeBitmap(initial...)
|
||||
_ = bm.Union(a1BM)
|
||||
}
|
||||
})
|
||||
b.Run("UnionInPlace1", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bm := NewBTreeBitmap(initial...)
|
||||
bm.UnionInPlace(a1BM)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Union2", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bm := NewBTreeBitmap(initial...)
|
||||
_ = bm.Union(a1BM, a2BM)
|
||||
}
|
||||
})
|
||||
b.Run("UnionInPlace2", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bm := NewBTreeBitmap(initial...)
|
||||
bm.UnionInPlace(a1BM, a2BM)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1275,7 +1275,7 @@ func isAllType(b *roaring.Bitmap, typ string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func getBenchData(b *testing.B) *benchmarkSampleData {
|
||||
func getBenchData(tb testing.TB) *benchmarkSampleData {
|
||||
data := &sampleData
|
||||
if data.a1 == nil {
|
||||
const max = (1 << 24) / 64
|
||||
|
|
@ -1321,19 +1321,19 @@ func getBenchData(b *testing.B) *benchmarkSampleData {
|
|||
|
||||
}
|
||||
if !isAllType(data.a1, "array") {
|
||||
b.Fatalf("expected data.a1 to be an array, it wasn't.")
|
||||
tb.Fatalf("expected data.a1 to be an array, it wasn't.")
|
||||
}
|
||||
if !isAllType(data.a2, "array") {
|
||||
b.Fatalf("expected data.a2 to be an array, it wasn't.")
|
||||
tb.Fatalf("expected data.a2 to be an array, it wasn't.")
|
||||
}
|
||||
if !isAllType(data.b, "bitmap") {
|
||||
b.Fatalf("expected data.b to be a bitmap, it wasn't.")
|
||||
tb.Fatalf("expected data.b to be a bitmap, it wasn't.")
|
||||
}
|
||||
if !isAllType(data.r1, "run") {
|
||||
b.Fatalf("expected data.r1 to be RLE, it wasn't.")
|
||||
tb.Fatalf("expected data.r1 to be RLE, it wasn't.")
|
||||
}
|
||||
if !isAllType(data.r2, "run") {
|
||||
b.Fatalf("expected data.r2 to be RLE, it wasn't.")
|
||||
tb.Fatalf("expected data.r2 to be RLE, it wasn't.")
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
|
@ -1607,8 +1607,8 @@ func BenchmarkUnion(b *testing.B) {
|
|||
|
||||
func BenchmarkUnionBulk(b *testing.B) {
|
||||
data := getBenchData(b)
|
||||
bm := roaring.NewBitmap()
|
||||
for n := 0; n < b.N; n++ {
|
||||
bm := roaring.NewBitmap()
|
||||
bm.
|
||||
UnionInPlace(data.a1, data.a2, data.b, data.r1, data.r2)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue