Skip to content

Commit

Permalink
query/store: memoize PromLabels() call (#7767)
Browse files Browse the repository at this point in the history
We use the stringlabels call so some allocations are inevitable but we
can be much smarter about it:

```
func (s *storeSeriesSet) At() (labels.Labels, []*storepb.AggrChunk) {
	return s.series[s.i].PromLabels(), s.series[s.i].Chunks <--- not memoized, new alloc on every At() call; need to memoize because of stringlabel. One alloc is inevitable.
}
```

```
lset, chks := s.SeriesSet.At()
if s.peek == nil {
	s.peek = &Series{Labels: labelpb.PromLabelsToLabelpbLabels(lset), Chunks: chks} <-- converting back to labelpb ?
	continue
}
```

```
if labels.Compare(lset, s.peek.PromLabels()) != 0 { <--- PromLabels() called; we can avoid this call
	s.lset, s.chunks = s.peek.PromLabels(), s.peek.Chunks <- PromLabels() called; we can avoid this
	s.peek = &Series{Labels: labelpb.PromLabelsToLabelpbLabels(lset), Chunks: chks} <--- converting back to labelpb; we can avoid this
	return true
}
```

Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>
  • Loading branch information
GiedriusS committed Sep 20, 2024
1 parent 30f453e commit 735db72
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
10 changes: 8 additions & 2 deletions pkg/query/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ type storeSeriesSet struct {
// TODO(bwplotka): Don't buffer all, we have to buffer single series (to sort and dedup chunks), but nothing more.
series []storepb.Series
i int

promLabels []labels.Labels
}

func newStoreSeriesSet(s []storepb.Series) *storeSeriesSet {
return &storeSeriesSet{series: s, i: -1}
return &storeSeriesSet{series: s, i: -1, promLabels: make([]labels.Labels, len(s))}
}

func (s *storeSeriesSet) Next() bool {
Expand All @@ -83,7 +85,11 @@ func (*storeSeriesSet) Err() error {
}

func (s *storeSeriesSet) At() (labels.Labels, []*storepb.AggrChunk) {
return s.series[s.i].PromLabels(), s.series[s.i].Chunks
// stringlabels are immutable, so we can cache them.
if s.promLabels[s.i].IsEmpty() {
s.promLabels[s.i] = s.series[s.i].PromLabels()
}
return s.promLabels[s.i], s.series[s.i].Chunks
}

// chunkSeries implements storage.Series for a series on storepb types.
Expand Down
22 changes: 16 additions & 6 deletions pkg/store/storepb/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,18 @@ Outer:
return true
}

type seriesWithLabels struct {
*Series

labels.Labels
}

// uniqueSeriesSet takes one series set and ensures each iteration contains single, full series.
type uniqueSeriesSet struct {
SeriesSet
done bool

peek *Series
peek *seriesWithLabels

lset labels.Labels
chunks []*AggrChunk
Expand All @@ -244,13 +250,17 @@ func (s *uniqueSeriesSet) Next() bool {
}
lset, chks := s.SeriesSet.At()
if s.peek == nil {
s.peek = &Series{Labels: labelpb.PromLabelsToLabelpbLabels(lset), Chunks: chks}
s.peek = &seriesWithLabels{Series: &Series{
Chunks: chks,
}, Labels: lset}
continue
}

if labels.Compare(lset, s.peek.PromLabels()) != 0 {
s.lset, s.chunks = s.peek.PromLabels(), s.peek.Chunks
s.peek = &Series{Labels: labelpb.PromLabelsToLabelpbLabels(lset), Chunks: chks}
if labels.Compare(lset, s.peek.Labels) != 0 {
s.lset, s.chunks = s.peek.Labels, s.peek.Chunks
s.peek = &seriesWithLabels{Series: &Series{
Chunks: chks,
}, Labels: lset}
return true
}

Expand All @@ -263,7 +273,7 @@ func (s *uniqueSeriesSet) Next() bool {
return false
}

s.lset, s.chunks = s.peek.PromLabels(), s.peek.Chunks
s.lset, s.chunks = s.peek.Labels, s.peek.Chunks
s.peek = nil
return true
}
Expand Down

0 comments on commit 735db72

Please sign in to comment.