Skip to content

Commit

Permalink
Improve gauge performance
Browse files Browse the repository at this point in the history
  • Loading branch information
zalegrala committed Nov 1, 2024
1 parent 44c18cc commit 6337bcc
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 34 deletions.
47 changes: 23 additions & 24 deletions modules/generator/registry/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ type gauge struct {

onAddSeries func(count uint32) bool
onRemoveSeries func(count uint32)

externalLabels map[string]string
}

type gaugeSeries struct {
// labelValueCombo should not be modified after creation
labels LabelPair
value *atomic.Float64
lastUpdated *atomic.Int64
lb *labels.Builder
baseLabels labels.Labels
}

var (
Expand All @@ -43,7 +47,7 @@ const (
set = "set"
)

func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32)) *gauge {
func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32), externalLabels map[string]string) *gauge {
if onAddSeries == nil {
onAddSeries = func(uint32) bool {
return true
Expand All @@ -58,6 +62,7 @@ func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(co
series: make(map[uint64]*gaugeSeries),
onAddSeries: onAddSeries,
onRemoveSeries: onRemoveSeries,
externalLabels: externalLabels,
}
}

Expand Down Expand Up @@ -107,10 +112,23 @@ func (g *gauge) updateSeries(labelValueCombo *LabelValueCombo, value float64, op
}

func (g *gauge) newSeries(labelValueCombo *LabelValueCombo, value float64) *gaugeSeries {
// base labels
baseLabels := make(labels.Labels, 1+len(g.externalLabels))

// add metric name
baseLabels = append(baseLabels, labels.Label{Name: labels.MetricName, Value: g.metricName})

// add external labels
for name, value := range g.externalLabels {
baseLabels = append(baseLabels, labels.Label{Name: name, Value: value})
}

return &gaugeSeries{
labels: labelValueCombo.getLabelPair(),
value: atomic.NewFloat64(value),
lastUpdated: atomic.NewInt64(time.Now().UnixMilli()),
lb: labels.NewBuilder(baseLabels),
baseLabels: baseLabels,
}
}

Expand All @@ -127,43 +145,24 @@ func (g *gauge) name() string {
return g.metricName
}

func (g *gauge) collectMetrics(appender storage.Appender, timeMs int64, externalLabels map[string]string) (activeSeries int, err error) {
func (g *gauge) collectMetrics(appender storage.Appender, timeMs int64, _ map[string]string) (activeSeries int, err error) {
g.seriesMtx.RLock()
defer g.seriesMtx.RUnlock()

activeSeries = len(g.series)

labelsCount := 0
if activeSeries > 0 && g.series[0] != nil {
labelsCount = len(g.series[0].labels.names)
}

// base labels
baseLabels := make(labels.Labels, 1+len(externalLabels)+labelsCount)

// add metric name
baseLabels = append(baseLabels, labels.Label{Name: labels.MetricName, Value: g.metricName})

// add external labels
for name, value := range externalLabels {
baseLabels = append(baseLabels, labels.Label{Name: name, Value: value})
}

// TODO: avoid allocation on each collection
lb := labels.NewBuilder(baseLabels)

for _, s := range g.series {
t := time.UnixMilli(timeMs)

// reset labels for every series
lb.Reset(baseLabels)
s.lb.Reset(s.baseLabels)

// set series-specific labels
for i, name := range s.labels.names {
lb.Set(name, s.labels.values[i])
s.lb.Set(name, s.labels.values[i])
}

_, err = appender.Append(0, lb.Labels(), t.UnixMilli(), s.value.Load())
_, err = appender.Append(0, s.lb.Labels(), t.UnixMilli(), s.value.Load())
if err != nil {
return
}
Expand Down
18 changes: 9 additions & 9 deletions modules/generator/registry/gauge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func Test_gaugeInc(t *testing.T) {
return true
}

c := newGauge("my_gauge", onAdd, nil)
c := newGauge("my_gauge", onAdd, nil, nil)

c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0)
c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0)
Expand Down Expand Up @@ -52,7 +52,7 @@ func TestGaugeDifferentLabels(t *testing.T) {
return true
}

c := newGauge("my_gauge", onAdd, nil)
c := newGauge("my_gauge", onAdd, nil, nil)

c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0)
c.Inc(newLabelValueCombo([]string{"another_label"}, []string{"another_value"}), 2.0)
Expand All @@ -74,7 +74,7 @@ func Test_gaugeSet(t *testing.T) {
return true
}

c := newGauge("my_gauge", onAdd, nil)
c := newGauge("my_gauge", onAdd, nil, nil)

c.Set(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0)
c.Set(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0)
Expand Down Expand Up @@ -109,7 +109,7 @@ func Test_gauge_cantAdd(t *testing.T) {
return canAdd
}

c := newGauge("my_gauge", onAdd, nil)
c := newGauge("my_gauge", onAdd, nil, nil)

// allow adding new series
canAdd = true
Expand Down Expand Up @@ -145,7 +145,7 @@ func Test_gauge_removeStaleSeries(t *testing.T) {
removedSeries++
}

c := newGauge("my_gauge", nil, onRemove)
c := newGauge("my_gauge", nil, onRemove, nil)

timeMs := time.Now().UnixMilli()
c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0)
Expand Down Expand Up @@ -180,7 +180,7 @@ func Test_gauge_removeStaleSeries(t *testing.T) {
}

func Test_gauge_externalLabels(t *testing.T) {
c := newGauge("my_gauge", nil, nil)
c := newGauge("my_gauge", nil, nil, map[string]string{"external_label": "external_value"})

c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0)
c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0)
Expand All @@ -190,11 +190,11 @@ func Test_gauge_externalLabels(t *testing.T) {
newSample(map[string]string{"__name__": "my_gauge", "label": "value-1", "external_label": "external_value"}, collectionTimeMs, 1),
newSample(map[string]string{"__name__": "my_gauge", "label": "value-2", "external_label": "external_value"}, collectionTimeMs, 2),
}
collectMetricAndAssert(t, c, collectionTimeMs, map[string]string{"external_label": "external_value"}, 2, expectedSamples, nil)
collectMetricAndAssert(t, c, collectionTimeMs, nil, 2, expectedSamples, nil)
}

func Test_gauge_concurrencyDataRace(t *testing.T) {
c := newGauge("my_gauge", nil, nil)
c := newGauge("my_gauge", nil, nil, nil)

end := make(chan struct{})

Expand Down Expand Up @@ -240,7 +240,7 @@ func Test_gauge_concurrencyDataRace(t *testing.T) {
}

func Test_gauge_concurrencyCorrectness(t *testing.T) {
c := newGauge("my_gauge", nil, nil)
c := newGauge("my_gauge", nil, nil, nil)

var wg sync.WaitGroup
end := make(chan struct{})
Expand Down
2 changes: 1 addition & 1 deletion modules/generator/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func (r *ManagedRegistry) NewHistogram(name string, buckets []float64, histogram
}

func (r *ManagedRegistry) NewGauge(name string) Gauge {
g := newGauge(name, r.onAddMetricSeries, r.onRemoveMetricSeries)
g := newGauge(name, r.onAddMetricSeries, r.onRemoveMetricSeries, r.externalLabels)
r.registerMetric(g)
return g
}
Expand Down

0 comments on commit 6337bcc

Please sign in to comment.