This commit is contained in:
Aliaksandr Valialkin 2024-05-15 16:50:26 +02:00
parent 15c66abbe0
commit 6026112913
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
4 changed files with 75 additions and 8 deletions

View file

@ -146,6 +146,28 @@ func (bm *bitmap) forEachSetBit(f func(idx int) bool) {
}
}
// forEachSetBitReadonly calls f for each set bit
func (bm *bitmap) forEachSetBitReadonly(f func(idx int)) {
a := bm.a
bitsLen := bm.bitsLen
for i, word := range a {
if word == 0 {
continue
}
for j := 0; j < 64; j++ {
mask := uint64(1) << j
if (word & mask) == 0 {
continue
}
idx := i*64 + j
if idx >= bitsLen {
break
}
f(idx)
}
}
}
func (bm *bitmap) onesCount() int {
n := 0
for _, word := range bm.a {

View file

@ -32,7 +32,7 @@ func TestBitmap(t *testing.T) {
// Make sure that all the bits are set.
nextIdx := 0
bm.forEachSetBit(func(idx int) bool {
bm.forEachSetBitReadonly(func(idx int) {
if idx >= i {
t.Fatalf("index must be smaller than %d", i)
}
@ -40,7 +40,6 @@ func TestBitmap(t *testing.T) {
t.Fatalf("unexpected idx; got %d; want %d", idx, nextIdx)
}
nextIdx++
return true
})
if !bm.areAllBitsSet() {
@ -66,12 +65,11 @@ func TestBitmap(t *testing.T) {
}
nextIdx = 1
bm.forEachSetBit(func(idx int) bool {
bm.forEachSetBitReadonly(func(idx int) {
if idx != nextIdx {
t.Fatalf("unexpected idx; got %d; want %d", idx, nextIdx)
}
nextIdx += 2
return true
})
// Clear all the bits
@ -93,9 +91,8 @@ func TestBitmap(t *testing.T) {
}
bitsCount := 0
bm.forEachSetBit(func(_ int) bool {
bm.forEachSetBitReadonly(func(_ int) {
bitsCount++
return true
})
if bitsCount != 0 {
t.Fatalf("unexpected non-zero number of set bits remained: %d", bitsCount)

View file

@ -4,6 +4,35 @@ import (
"testing"
)
func BenchmarkBitmapForEachSetBitReadonly(b *testing.B) {
const bitsLen = 64*1024
b.Run("no-zero-bits", func(b *testing.B) {
bm := getBitmap(bitsLen)
bm.setBits()
benchmarkBitmapForEachSetBitReadonly(b, bm)
putBitmap(bm)
})
b.Run("half-zero-bits", func(b *testing.B) {
bm := getBitmap(bitsLen)
bm.setBits()
bm.forEachSetBit(func(idx int) bool {
return idx%2 == 0
})
benchmarkBitmapForEachSetBitReadonly(b, bm)
putBitmap(bm)
})
b.Run("one-set-bit", func(b *testing.B) {
bm := getBitmap(bitsLen)
bm.setBits()
bm.forEachSetBit(func(idx int) bool {
return idx == bitsLen/2
})
benchmarkBitmapForEachSetBitReadonly(b, bm)
putBitmap(bm)
})
}
func BenchmarkBitmapForEachSetBit(b *testing.B) {
const bitsLen = 64*1024
@ -57,14 +86,33 @@ func BenchmarkBitmapForEachSetBit(b *testing.B) {
})
}
func benchmarkBitmapForEachSetBitReadonly(b *testing.B, bm *bitmap) {
b.SetBytes(int64(bm.bitsLen))
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
bmLocal := getBitmap(bm.bitsLen)
n := 0
for pb.Next() {
bmLocal.copyFrom(bm)
bmLocal.forEachSetBitReadonly(func(idx int) {
n++
})
}
putBitmap(bmLocal)
GlobalSink.Add(uint64(n))
})
}
func benchmarkBitmapForEachSetBit(b *testing.B, bm *bitmap, isClearBits bool) {
b.SetBytes(int64(bm.bitsLen))
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
bmLocal := getBitmap(bm.bitsLen)
n := 0
for pb.Next() {
bmLocal.copyFrom(bm)
bmLocal.forEachSetBit(func(idx int) bool {
n++
return !isClearBits
})
if isClearBits {
@ -78,5 +126,6 @@ func benchmarkBitmapForEachSetBit(b *testing.B, bm *bitmap, isClearBits bool) {
}
}
putBitmap(bmLocal)
GlobalSink.Add(uint64(n))
})
}

View file

@ -278,10 +278,9 @@ func (br *blockResult) mustInit(bs *blockSearch, bm *bitmap) {
// Slow path - copy only the needed timestamps to br according to filter results.
dstTimestamps := br.timestamps[:0]
bm.forEachSetBit(func(idx int) bool {
bm.forEachSetBitReadonly(func(idx int) {
ts := srcTimestamps[idx]
dstTimestamps = append(dstTimestamps, ts)
return true
})
br.timestamps = dstTimestamps
}