Skip to content

Commit

Permalink
Improve counter performance
Browse files Browse the repository at this point in the history
  • Loading branch information
zalegrala committed Nov 1, 2024
1 parent 6337bcc commit 8a47773
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 37 deletions.
48 changes: 24 additions & 24 deletions modules/generator/registry/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type counter struct {

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

externalLabels map[string]string
}

type counterSeries struct {
Expand All @@ -31,6 +33,9 @@ type counterSeries struct {
// to the desired value. This avoids Prometheus throwing away the first
// value in the series, due to the transition from null -> x.
firstSeries *atomic.Bool

lb *labels.Builder
baseLabels labels.Labels
}

var (
Expand All @@ -46,7 +51,7 @@ func (co *counterSeries) registerSeenSeries() {
co.firstSeries.Store(false)
}

func newCounter(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32)) *counter {
func newCounter(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32), externalLabels map[string]string) *counter {
if onAddSeries == nil {
onAddSeries = func(uint32) bool {
return true
Expand All @@ -61,6 +66,7 @@ func newCounter(name string, onAddSeries func(uint32) bool, onRemoveSeries func(
series: make(map[uint64]*counterSeries),
onAddSeries: onAddSeries,
onRemoveSeries: onRemoveSeries,
externalLabels: externalLabels,
}
}

Expand Down Expand Up @@ -98,11 +104,24 @@ func (c *counter) Inc(labelValueCombo *LabelValueCombo, value float64) {
}

func (c *counter) newSeries(labelValueCombo *LabelValueCombo, value float64) *counterSeries {
// base labels
baseLabels := make(labels.Labels, 0, 1+len(c.externalLabels))

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

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

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

Expand All @@ -121,31 +140,12 @@ func (c *counter) collectMetrics(appender storage.Appender, timeMs int64, extern

activeSeries = len(c.series)

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

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

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

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

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

for _, s := range c.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])
}

// If we are about to call Append for the first time on a series, we need
Expand All @@ -155,14 +155,14 @@ func (c *counter) collectMetrics(appender storage.Appender, timeMs int64, extern
// We set the timestamp of the init serie at the end of the previous minute, that way we ensure it ends in a
// different aggregation interval to avoid be downsampled.
endOfLastMinuteMs := getEndOfLastMinuteMs(timeMs)
_, err = appender.Append(0, lb.Labels(), endOfLastMinuteMs, 0)
_, err = appender.Append(0, s.lb.Labels(), endOfLastMinuteMs, 0)
if err != nil {
return
}
s.registerSeenSeries()
}

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

c := newCounter("my_counter", onAdd, nil)
c := newCounter("my_counter", onAdd, 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 @@ -28,10 +28,10 @@ func Test_counter(t *testing.T) {
collectionTimeMs := time.Now().UnixMilli()
endOfLastMinuteMs := getEndOfLastMinuteMs(collectionTimeMs)
expectedSamples := []sample{
newSample(map[string]string{"__name__": "my_counter", "label": "value-1"}, endOfLastMinuteMs, 0),
newSample(map[string]string{"__name__": "my_counter", "label": "value-1"}, collectionTimeMs, 1),
newSample(map[string]string{"__name__": "my_counter", "label": "value-2"}, endOfLastMinuteMs, 0),
newSample(map[string]string{"__name__": "my_counter", "label": "value-2"}, collectionTimeMs, 2),
newSample(map[string]string{"__name__": "my_counter", "label": "value-1", "external_label": "external_value"}, endOfLastMinuteMs, 0),
newSample(map[string]string{"__name__": "my_counter", "label": "value-1", "external_label": "external_value"}, collectionTimeMs, 1),
newSample(map[string]string{"__name__": "my_counter", "label": "value-2", "external_label": "external_value"}, endOfLastMinuteMs, 0),
newSample(map[string]string{"__name__": "my_counter", "label": "value-2", "external_label": "external_value"}, collectionTimeMs, 2),
}
collectMetricAndAssert(t, c, collectionTimeMs, nil, 2, expectedSamples, nil)

Expand Down Expand Up @@ -59,7 +59,7 @@ func TestCounterDifferentLabels(t *testing.T) {
return true
}

c := newCounter("my_counter", onAdd, nil)
c := newCounter("my_counter", 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 @@ -84,7 +84,7 @@ func Test_counter_cantAdd(t *testing.T) {
return canAdd
}

c := newCounter("my_counter", onAdd, nil)
c := newCounter("my_counter", onAdd, nil, nil)

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

c := newCounter("my_counter", nil, onRemove)
c := newCounter("my_counter", nil, onRemove, nil)

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

func Test_counter_externalLabels(t *testing.T) {
c := newCounter("my_counter", nil, nil)
c := newCounter("my_counter", 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 @@ -174,11 +174,11 @@ func Test_counter_externalLabels(t *testing.T) {
newSample(map[string]string{"__name__": "my_counter", "label": "value-2", "external_label": "external_value"}, endOfLastMinuteMs, 0),
newSample(map[string]string{"__name__": "my_counter", "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_counter_concurrencyDataRace(t *testing.T) {
c := newCounter("my_counter", nil, nil)
c := newCounter("my_counter", nil, nil, nil)

end := make(chan struct{})

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

func Test_counter_concurrencyCorrectness(t *testing.T) {
c := newCounter("my_counter", nil, nil)
c := newCounter("my_counter", 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 @@ -144,7 +144,7 @@ func (r *ManagedRegistry) NewLabelValueCombo(labels []string, values []string) *
}

func (r *ManagedRegistry) NewCounter(name string) Counter {
c := newCounter(name, r.onAddMetricSeries, r.onRemoveMetricSeries)
c := newCounter(name, r.onAddMetricSeries, r.onRemoveMetricSeries, r.externalLabels)
r.registerMetric(c)
return c
}
Expand Down

0 comments on commit 8a47773

Please sign in to comment.