From 7fb015cc7f88391f9e7ffcc3ad492b1b09d0d536 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Tue, 20 Nov 2018 11:55:04 -0700 Subject: [PATCH] chore: Add GroupBy benchmark --- pkg/testing/gen/sequence.go | 59 +++++++++++++++++ pkg/testing/gen/tags_sequence.go | 93 +++++++++++++++++++++++++++ storage/reads/group_resultset_test.go | 33 ++++++++++ 3 files changed, 185 insertions(+) create mode 100644 pkg/testing/gen/sequence.go create mode 100644 pkg/testing/gen/tags_sequence.go diff --git a/pkg/testing/gen/sequence.go b/pkg/testing/gen/sequence.go new file mode 100644 index 0000000000..3942998821 --- /dev/null +++ b/pkg/testing/gen/sequence.go @@ -0,0 +1,59 @@ +package gen + +import ( + "fmt" + "math" +) + +type Sequence interface { + Next() bool + Value() string + Count() int +} + +type CounterByteSequence struct { + format string + nfmt string + val string + s int + v int + end int +} + +func NewCounterByteSequenceCount(n int) *CounterByteSequence { + return NewCounterByteSequence("value%s", 0, n) +} + +func NewCounterByteSequence(format string, start, end int) *CounterByteSequence { + s := &CounterByteSequence{ + format: format, + nfmt: fmt.Sprintf("%%0%dd", int(math.Ceil(math.Log10(float64(end))))), + s: start, + v: start, + end: end, + } + s.update() + return s +} + +func (s *CounterByteSequence) Next() bool { + s.v++ + if s.v >= s.end { + s.v = s.s + } + s.update() + return true +} + +func (s *CounterByteSequence) update() { + s.val = fmt.Sprintf(s.format, fmt.Sprintf(s.nfmt, s.v)) +} + +func (s *CounterByteSequence) Count() int { return s.end - s.s } +func (s *CounterByteSequence) Value() string { return s.val } + +type ConstantStringSequence string + +func (ConstantStringSequence) Next() bool { return true } +func (s ConstantStringSequence) Value() string { return string(s) } +func (ConstantStringSequence) Count() int { return 1 } diff --git a/pkg/testing/gen/tags_sequence.go b/pkg/testing/gen/tags_sequence.go new file mode 100644 index 0000000000..26b7889842 --- /dev/null +++ b/pkg/testing/gen/tags_sequence.go @@ -0,0 +1,93 @@ +package gen + +import ( + "fmt" + "math" + "sort" + + "github.com/influxdata/influxdb/models" +) + +type TagsSequence interface { + Next() bool + Value() models.Tags + Count() int +} + +type TagsValuesSequence struct { + tags models.Tags + vals []Sequence + n int + max int +} + +func NewTagsValuesSequenceKeysValues(keys []string, vals []Sequence) *TagsValuesSequence { + tm := make(map[string]string, len(keys)) + for _, k := range keys { + tm[k] = "" + } + + count := 1 + for i := range vals { + count *= vals[i].Count() + } + + // models.Tags are ordered, so ensure vals are ordered with respect to keys + sort.Sort(keyValues{keys, vals}) + + return &TagsValuesSequence{ + tags: models.NewTags(tm), + vals: vals, + max: count, + } +} + +func NewTagsValuesSequenceValues(prefix string, vals []Sequence) *TagsValuesSequence { + keys := make([]string, len(vals)) + // max tag width + tw := int(math.Ceil(math.Log10(float64(len(vals))))) + tf := fmt.Sprintf("%s%%0%dd", prefix, tw) + for i := range vals { + keys[i] = fmt.Sprintf(tf, i) + } + return NewTagsValuesSequenceKeysValues(keys, vals) +} + +func (s *TagsValuesSequence) Next() bool { + if s.n >= s.max { + return false + } + + for i := range s.vals { + s.tags[i].Value = []byte(s.vals[i].Value()) + } + + s.n++ + i := s.n + for j := len(s.vals) - 1; j >= 0; j-- { + v := s.vals[j] + v.Next() + c := v.Count() + if r := i % c; r != 0 { + break + } + i /= c + } + + return true +} + +func (s *TagsValuesSequence) Value() models.Tags { return s.tags } +func (s *TagsValuesSequence) Count() int { return s.max } + +type keyValues struct { + keys []string + vals []Sequence +} + +func (k keyValues) Len() int { return len(k.keys) } +func (k keyValues) Less(i, j int) bool { return k.keys[i] < k.keys[j] } +func (k keyValues) Swap(i, j int) { + k.keys[i], k.keys[j] = k.keys[j], k.keys[i] + k.vals[i], k.vals[j] = k.vals[j], k.vals[i] +} diff --git a/storage/reads/group_resultset_test.go b/storage/reads/group_resultset_test.go index 2aedee8e72..d8a6c59103 100644 --- a/storage/reads/group_resultset_test.go +++ b/storage/reads/group_resultset_test.go @@ -307,3 +307,36 @@ func (s *sliceSeriesCursor) Next() *reads.SeriesRow { } return nil } + +func BenchmarkNewGroupResultSet_GroupBy(b *testing.B) { + card := []int{10, 10, 10} + vals := make([]gen.Sequence, len(card)) + for i := range card { + vals[i] = gen.NewCounterByteSequenceCount(card[i]) + } + + tags := gen.NewTagsValuesSequenceValues("tag", vals) + rows := make([]reads.SeriesRow, tags.Count()) + for i := range rows { + tags.Next() + t := tags.Value().Clone() + rows[i].SeriesTags = t + rows[i].Tags = t + rows[i].Name = []byte("m0") + } + + cur := &sliceSeriesCursor{rows: rows} + newCursor := func() (reads.SeriesCursor, error) { + cur.i = 0 + return cur, nil + } + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + var hints datatypes.HintFlags + hints.SetHintSchemaAllTime() + rs := reads.NewGroupResultSet(context.Background(), &datatypes.ReadRequest{Group: datatypes.GroupBy, GroupKeys: []string{"tag2"}, Hints: hints}, newCursor) + rs.Close() + } +}