Prometheus: Reduce memory allocations in QueryData.processExemplars (#63373)

* tsdb/prometheus/querydata: Reduce memory allocations in QueryData.processExemplars

---------

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Arve Knudsen
2023-03-22 10:59:39 +01:00
committed by GitHub
parent 6d5242e54c
commit f7ee42d871
6 changed files with 41 additions and 27 deletions
@@ -55,22 +55,29 @@ func (f *Framer) Frames() (data.Frames, error) {
valueField := data.NewField(data.TimeSeriesValueFieldName, nil, make([]float64, 0, len(exemplars)))
exemplarFrame.Fields = append(exemplarFrame.Fields, timeField, valueField)
labelNames := f.labelTracker.GetNames()
exemplarLabels := make(map[string]string, len(labelNames))
for _, labelName := range labelNames {
exemplarFrame.Fields = append(exemplarFrame.Fields, data.NewField(labelName, nil, make([]string, 0, len(exemplars))))
}
// add the sampled exemplars to the new exemplar frame
for _, b := range exemplars {
// Fill labels map with default values
for _, n := range labelNames {
exemplarLabels[n] = b.SeriesLabels[n]
}
// Enter corresponding label values from exemplar fields
for _, bf := range b.Fields {
if _, exists := exemplarLabels[bf.Name]; exists {
exemplarLabels[bf.Name] = bf.CopyAt(b.RowIdx).(string)
}
}
timeField.Append(b.Timestamp)
valueField.Append(b.Value)
for i, labelName := range labelNames {
labelValue, ok := b.Labels[labelName]
if !ok {
// if the label is not present in the exemplar labels, then use the series label
labelValue = b.SeriesLabels[labelName]
}
colIdx := i + 2 // +2 to skip time and value fields
exemplarFrame.Fields[colIdx].Append(labelValue)
exemplarFrame.Fields[colIdx].Append(exemplarLabels[labelName])
}
}
@@ -1,11 +1,16 @@
package exemplar
import "sort"
import (
"sort"
"github.com/grafana/grafana-plugin-sdk-go/data"
)
var _ LabelTracker = (*labelTracker)(nil)
type LabelTracker interface {
Add(labels map[string]string)
AddFields(fields []*data.Field)
GetNames() []string
}
@@ -23,9 +28,14 @@ func NewLabelTracker() LabelTracker {
// so that they can be used to build the label fields in the exemplar frame
func (l *labelTracker) Add(labels map[string]string) {
for k := range labels {
if _, ok := l.labelSet[k]; !ok {
l.labelSet[k] = struct{}{}
}
l.labelSet[k] = struct{}{}
}
}
// AddFields saves field names so that they can be used to build the label fields in the exemplar frame.
func (l *labelTracker) AddFields(fields []*data.Field) {
for _, f := range fields {
l.labelSet[f.Name] = struct{}{}
}
}