From 07674d859cfbc9fa22c9122acfe1113bb4c6f7b5 Mon Sep 17 00:00:00 2001 From: Seebs Date: Thu, 3 Jan 2019 13:50:00 -0600 Subject: [PATCH] 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. --- fragment_internal_test.go | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/fragment_internal_test.go b/fragment_internal_test.go index cca88dda1..c7a999848 100644 --- a/fragment_internal_test.go +++ b/fragment_internal_test.go @@ -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, "")