From 671a0cf5c6d5527eea218eb5f48c6724db37bfba Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 18 May 2021 14:03:53 -0500 Subject: [PATCH] tweak ImportValue benchmark With timestamps, we probably want to at least check larger BSI fields, so we add that. Also, tweak the interpretation of b.N (making each N count for 10,000 bits) so we can see allocation load at all. But we also reduce the sparse set to be about one bit per 19 bits, because if we do one per 70,000, and are doing field-at-a-time imports, we're getting hundreds of imports to try to match a target of, say, around a million values. We also sort the inputs, because ImportValue is about to start requiring that, since the API does it anyway. Also, extend this to be available on Fields, because field.ImportValue is ALSO doing things which could be inefficient or expensive. --- field_internal_test.go | 36 ++++++++++++++++++++++++-- fragment_internal_test.go | 54 ++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 17 deletions(-) diff --git a/field_internal_test.go b/field_internal_test.go index 8a9ba7ebe..23f84bc4c 100644 --- a/field_internal_test.go +++ b/field_internal_test.go @@ -203,7 +203,7 @@ type TestField struct { } // NewTestField returns a new instance of TestField d/0. -func NewTestField(t *testing.T, opts FieldOption) *TestField { +func NewTestField(t testing.TB, opts FieldOption) *TestField { path, err := testhook.TempDirInDir(t, *TempDir, "pilosa-field-") if err != nil { t.Fatal(err) @@ -230,7 +230,7 @@ func NewTestField(t *testing.T, opts FieldOption) *TestField { } // OpenField returns a new, opened field at a temporary path. -func OpenField(t *testing.T, opts FieldOption) *TestField { +func OpenField(t testing.TB, opts FieldOption) *TestField { f := NewTestField(t, opts) return f } @@ -509,6 +509,38 @@ func TestBSIGroup_importValue(t *testing.T) { } // loop } +// benchmarkImportValues is a helper function to explore, very roughly, the cost +// of setting values using the special setter used for imports. +func benchmarkFieldImportValues(b *testing.B, qcx *Qcx, bitDepth uint64, f *TestField, cfunc func(uint64) uint64) { + batches := makeBenchmarkImportValueData(b, bitDepth, cfunc) + for _, req := range batches { + err := f.importValue(qcx, req.ColumnIDs, req.Values, &ImportOptions{}) + if err != nil { + b.Fatalf("error importing values: %s", err) + } + } +} + +// Benchmark performance of setValue for BSI ranges. +func BenchmarkField_ImportValue(b *testing.B) { + depths := []uint64{4, 8, 16, 32} + + for _, bitDepth := range depths { + f := OpenField(b, OptFieldTypeInt(0, 1< 0 { + req := ImportValueRequest{ColumnIDs: columns, Values: values} + batches = append(batches, req) + } + b.StartTimer() + return batches +} + // 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, tx Tx, bitDepth uint64, f *fragment, cfunc func(uint64) uint64) { - column := uint64(0) - b.StopTimer() - columns := make([]uint64, b.N) - values := make([]int64, b.N) - for i := 0; i < b.N; i++ { - values[i] = int64(i) - columns[i] = column - column = cfunc(column) - } - b.StartTimer() - err := f.importValue(tx, columns, values, bitDepth, false) - if err != nil { - b.Fatalf("error importing values: %s", err) + batches := makeBenchmarkImportValueData(b, bitDepth, cfunc) + for _, req := range batches { + err := f.importValue(tx, req.ColumnIDs, req.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 := []uint64{4, 8, 16} + depths := []uint64{4, 8, 16, 32} for _, bitDepth := range depths { name := fmt.Sprintf("Depth%d", bitDepth) f, idx, tx := mustOpenBSIFragment(b, "i", "f", viewBSIGroupPrefix+"foo", 0) _ = idx b.Run(name+"_Sparse", func(b *testing.B) { - benchmarkImportValues(b, tx, bitDepth, f, func(u uint64) uint64 { return (u + 70000) & (ShardWidth - 1) }) + benchmarkImportValues(b, tx, bitDepth, f, func(u uint64) uint64 { return (u + 19) & (ShardWidth - 1) }) }) f.Clean(b) f, idx, tx = mustOpenBSIFragment(b, "i", "f", viewBSIGroupPrefix+"foo", 0)