Skip to content

Commit a09a1d3

Browse files
authored
Reduce constrainLabels allocations (#1272)
* Add bench Signed-off-by: Bulat Khasanov <afti@yandex.ru> * Reduce constrainLabels allocations Signed-off-by: Bulat Khasanov <afti@yandex.ru> --------- Signed-off-by: Bulat Khasanov <afti@yandex.ru>
1 parent 8840afc commit a09a1d3

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

prometheus/vec.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ import (
2020
"github.com/prometheus/common/model"
2121
)
2222

23+
var labelsPool = &sync.Pool{
24+
New: func() interface{} {
25+
return make(Labels)
26+
},
27+
}
28+
29+
func getLabelsFromPool() Labels {
30+
return labelsPool.Get().(Labels)
31+
}
32+
33+
func putLabelsToPool(labels Labels) {
34+
for k := range labels {
35+
delete(labels, k)
36+
}
37+
38+
labelsPool.Put(labels)
39+
}
40+
2341
// MetricVec is a Collector to bundle metrics of the same name that differ in
2442
// their label values. MetricVec is not used directly but as a building block
2543
// for implementations of vectors of a given metric type, like GaugeVec,
@@ -93,6 +111,8 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
93111
// there for pros and cons of the two methods.
94112
func (m *MetricVec) Delete(labels Labels) bool {
95113
labels = constrainLabels(m.desc, labels)
114+
defer putLabelsToPool(labels)
115+
96116
h, err := m.hashLabels(labels)
97117
if err != nil {
98118
return false
@@ -109,6 +129,8 @@ func (m *MetricVec) Delete(labels Labels) bool {
109129
// To match curried labels with DeletePartialMatch, it must be called on the base vector.
110130
func (m *MetricVec) DeletePartialMatch(labels Labels) int {
111131
labels = constrainLabels(m.desc, labels)
132+
defer putLabelsToPool(labels)
133+
112134
return m.metricMap.deleteByLabels(labels, m.curry)
113135
}
114136

@@ -229,6 +251,8 @@ func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
229251
// for example GaugeVec.
230252
func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
231253
labels = constrainLabels(m.desc, labels)
254+
defer putLabelsToPool(labels)
255+
232256
h, err := m.hashLabels(labels)
233257
if err != nil {
234258
return nil, err
@@ -647,15 +671,16 @@ func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string {
647671
}
648672

649673
func constrainLabels(desc *Desc, labels Labels) Labels {
650-
constrainedValues := make(Labels, len(labels))
674+
constrainedLabels := getLabelsFromPool()
651675
for l, v := range labels {
652676
if i, ok := indexOf(l, desc.variableLabels.labelNames()); ok {
653-
constrainedValues[l] = desc.variableLabels[i].Constrain(v)
654-
continue
677+
v = desc.variableLabels[i].Constrain(v)
655678
}
656-
constrainedValues[l] = v
679+
680+
constrainedLabels[l] = v
657681
}
658-
return constrainedValues
682+
683+
return constrainedLabels
659684
}
660685

661686
func constrainLabelValues(desc *Desc, lvs []string, curry []curriedLabelValue) []string {

prometheus/vec_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,13 @@ func testConstrainedCurryVec(t *testing.T, vec *CounterVec, constraint func(stri
904904
})
905905
}
906906

907+
func BenchmarkMetricVecWithBasic(b *testing.B) {
908+
benchmarkMetricVecWith(b, Labels{
909+
"l1": "onevalue",
910+
"l2": "twovalue",
911+
})
912+
}
913+
907914
func BenchmarkMetricVecWithLabelValuesBasic(b *testing.B) {
908915
benchmarkMetricVecWithLabelValues(b, map[string][]string{
909916
"l1": {"onevalue"},
@@ -948,6 +955,27 @@ func benchmarkMetricVecWithLabelValuesCardinality(b *testing.B, nkeys, nvalues i
948955
benchmarkMetricVecWithLabelValues(b, labels)
949956
}
950957

958+
func benchmarkMetricVecWith(b *testing.B, labels map[string]string) {
959+
var keys []string
960+
for k := range labels {
961+
keys = append(keys, k)
962+
}
963+
964+
vec := NewGaugeVec(
965+
GaugeOpts{
966+
Name: "test",
967+
Help: "helpless",
968+
},
969+
keys,
970+
)
971+
972+
b.ReportAllocs()
973+
b.ResetTimer()
974+
for i := 0; i < b.N; i++ {
975+
vec.With(labels)
976+
}
977+
}
978+
951979
func benchmarkMetricVecWithLabelValues(b *testing.B, labels map[string][]string) {
952980
var keys []string
953981
for k := range labels { // Map order dependent, who cares though.

0 commit comments

Comments
 (0)