setValue test and benchmark updates

This provides a simple benchmark that can be used for
setValue, to give a way to compare results from adding BSI
support to roaring. Use the BSIGroup prefix for the
fragments, and specify a cache type of "none", to prevent
the use of a LRU cache (which makes things more expensive).

Add a parallel benchmark for ImportValue, so we can compare
them. (Unsurprisingly, the bulk-import endpoint is quite a
lot faster.)

Also, add a test for clearing values to the TestFragment_Sum
test; it turns out that this was never tested in this code,
but the http client test would test it and verify it, it should
probably also be tested here.
This commit is contained in:
Seebs 2019-01-03 13:50:00 -06:00
parent 7f6f9be88e
commit 07674d859c

View file

@ -367,6 +367,20 @@ func TestFragment_Sum(t *testing.T) {
t.Fatalf("unexpected sum: %d", sum)
}
})
// verify that clearValue clears values
if _, err := f.clearValue(1000, bitDepth, 23); err != nil {
t.Fatal(err)
}
t.Run("ClearValue", func(t *testing.T) {
if sum, n, err := f.sum(nil, bitDepth); err != nil {
t.Fatal(err)
} else if n != 3 {
t.Fatalf("unexpected count: %d", n)
} else if sum != (3800 - 382) {
t.Fatalf("unexpected sum: got %d, expecting %d", sum, 3800-382)
}
})
}
// Ensure a fragment can find the min and max of values.
@ -637,6 +651,71 @@ func TestFragment_Range(t *testing.T) {
})
}
// benchmarkSetValues is a helper function to explore, very roughly, the cost
// of setting values.
func benchmarkSetValues(b *testing.B, bitDepth uint, f *fragment, cfunc func(uint64) uint64) {
column := uint64(0)
for i := 0; i < b.N; i++ {
f.setValue(column, bitDepth, uint64(i))
column = cfunc(column)
}
}
// Benchmark performance of setValue for BSI ranges.
func BenchmarkFragment_SetValue(b *testing.B) {
depths := []uint{4, 8, 16}
for _, bitDepth := range depths {
name := fmt.Sprintf("Depth%d", bitDepth)
f := mustOpenFragment("i", "f", viewBSIGroupPrefix+"foo", 0, "none")
b.Run(name+"_Sparse", func(b *testing.B) {
benchmarkSetValues(b, bitDepth, f, func(u uint64) uint64 { return (u + 70000) & (ShardWidth - 1) })
})
f.Clean(b)
f = mustOpenFragment("i", "f", viewBSIGroupPrefix+"foo", 0, "none")
b.Run(name+"_Dense", func(b *testing.B) {
benchmarkSetValues(b, bitDepth, f, func(u uint64) uint64 { return (u + 1) & (ShardWidth - 1) })
})
f.Clean(b)
}
}
// benchmarkImportValues is a helper function to explore, very roughly, the cost
// of setting values using the special setter used for imports.
func benchmarkImportValues(b *testing.B, bitDepth uint, f *fragment, cfunc func(uint64) uint64) {
column := uint64(0)
b.StopTimer()
columns := make([]uint64, b.N)
values := make([]uint64, b.N)
for i := 0; i < b.N; i++ {
values[i] = uint64(i)
columns[i] = column
column = cfunc(column)
}
b.StartTimer()
err := f.importValue(columns, values, bitDepth, false)
if err != nil {
b.Fatalf("error importing values: %s", err)
}
}
// Benchmark performance of setValue for BSI ranges.
func BenchmarkFragment_ImportValue(b *testing.B) {
depths := []uint{4, 8, 16}
for _, bitDepth := range depths {
name := fmt.Sprintf("Depth%d", bitDepth)
f := mustOpenFragment("i", "f", viewBSIGroupPrefix+"foo", 0, "none")
b.Run(name+"_Sparse", func(b *testing.B) {
benchmarkImportValues(b, bitDepth, f, func(u uint64) uint64 { return (u + 70000) & (ShardWidth - 1) })
})
f.Clean(b)
f = mustOpenFragment("i", "f", viewBSIGroupPrefix+"foo", 0, "none")
b.Run(name+"_Dense", func(b *testing.B) {
benchmarkImportValues(b, bitDepth, f, func(u uint64) uint64 { return (u + 1) & (ShardWidth - 1) })
})
f.Clean(b)
}
}
// Ensure a fragment can snapshot correctly.
func TestFragment_Snapshot(t *testing.T) {
f := mustOpenFragment("i", "f", viewStandard, 0, "")