Skip to content

Commit c4004ef

Browse files
committed
benchmark: measure label resolution in MetricVec
Signed-off-by: Stephen J Day <[email protected]>
1 parent 25db044 commit c4004ef

File tree

7 files changed

+108
-57
lines changed

7 files changed

+108
-57
lines changed

prometheus/counter.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,15 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
9696
opts.ConstLabels,
9797
)
9898
return &CounterVec{
99-
MetricVec: MetricVec{
100-
children: map[uint64]Metric{},
101-
desc: desc,
102-
newMetric: func(lvs ...string) Metric {
103-
result := &counter{value: value{
104-
desc: desc,
105-
valType: CounterValue,
106-
labelPairs: makeLabelPairs(desc, lvs),
107-
}}
108-
result.init(result) // Init self-collection.
109-
return result
110-
},
111-
},
99+
MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
100+
result := &counter{value: value{
101+
desc: desc,
102+
valType: CounterValue,
103+
labelPairs: makeLabelPairs(desc, lvs),
104+
}}
105+
result.init(result) // Init self-collection.
106+
return result
107+
}),
112108
}
113109
}
114110

prometheus/gauge.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,9 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
7272
opts.ConstLabels,
7373
)
7474
return &GaugeVec{
75-
MetricVec: MetricVec{
76-
children: map[uint64]Metric{},
77-
desc: desc,
78-
newMetric: func(lvs ...string) Metric {
79-
return newValue(desc, GaugeValue, 0, lvs...)
80-
},
81-
},
75+
MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
76+
return newValue(desc, GaugeValue, 0, lvs...)
77+
}),
8278
}
8379
}
8480

prometheus/histogram.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,9 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
301301
opts.ConstLabels,
302302
)
303303
return &HistogramVec{
304-
MetricVec: MetricVec{
305-
children: map[uint64]Metric{},
306-
desc: desc,
307-
newMetric: func(lvs ...string) Metric {
308-
return newHistogram(desc, opts, lvs...)
309-
},
310-
},
304+
MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
305+
return newHistogram(desc, opts, lvs...)
306+
}),
311307
}
312308
}
313309

prometheus/summary.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,13 +404,9 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
404404
opts.ConstLabels,
405405
)
406406
return &SummaryVec{
407-
MetricVec: MetricVec{
408-
children: map[uint64]Metric{},
409-
desc: desc,
410-
newMetric: func(lvs ...string) Metric {
411-
return newSummary(desc, opts, lvs...)
412-
},
413-
},
407+
MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
408+
return newSummary(desc, opts, lvs...)
409+
}),
414410
}
415411
}
416412

prometheus/untyped.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,9 @@ func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
7070
opts.ConstLabels,
7171
)
7272
return &UntypedVec{
73-
MetricVec: MetricVec{
74-
children: map[uint64]Metric{},
75-
desc: desc,
76-
newMetric: func(lvs ...string) Metric {
77-
return newValue(desc, UntypedValue, 0, lvs...)
78-
},
79-
},
73+
MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
74+
return newValue(desc, UntypedValue, 0, lvs...)
75+
}),
8076
}
8177
}
8278

prometheus/vec.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ type MetricVec struct {
3131
newMetric func(labelValues ...string) Metric
3232
}
3333

34+
// newMetricVec returns an initialized MetricVec. The concrete value is
35+
// returned for embedding into another struct.
36+
func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) MetricVec {
37+
return MetricVec{
38+
children: map[uint64]Metric{},
39+
desc: desc,
40+
newMetric: newMetric,
41+
}
42+
}
43+
3444
// Describe implements Collector. The length of the returned slice
3545
// is always one.
3646
func (m *MetricVec) Describe(ch chan<- *Desc) {

prometheus/vec_test.go

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,12 @@
1414
package prometheus
1515

1616
import (
17+
"fmt"
1718
"testing"
1819
)
1920

2021
func TestDelete(t *testing.T) {
21-
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil)
22-
vec := MetricVec{
23-
children: map[uint64]Metric{},
24-
desc: desc,
25-
newMetric: func(lvs ...string) Metric {
26-
return newValue(desc, UntypedValue, 0, lvs...)
27-
},
28-
}
22+
vec := newUntypedMetricVec("test", "helpless", []string{"l1", "l2"})
2923

3024
if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want {
3125
t.Errorf("got %v, want %v", got, want)
@@ -57,14 +51,7 @@ func TestDelete(t *testing.T) {
5751
}
5852

5953
func TestDeleteLabelValues(t *testing.T) {
60-
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil)
61-
vec := MetricVec{
62-
children: map[uint64]Metric{},
63-
desc: desc,
64-
newMetric: func(lvs ...string) Metric {
65-
return newValue(desc, UntypedValue, 0, lvs...)
66-
},
67-
}
54+
vec := newUntypedMetricVec("test", "helpless", []string{"l1", "l2"})
6855

6956
if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want {
7057
t.Errorf("got %v, want %v", got, want)
@@ -86,3 +73,77 @@ func TestDeleteLabelValues(t *testing.T) {
8673
t.Errorf("got %v, want %v", got, want)
8774
}
8875
}
76+
77+
func newUntypedMetricVec(name, help string, labels []string) *MetricVec {
78+
desc := NewDesc("test", "helpless", labels, nil)
79+
vec := newMetricVec(desc, func(lvs ...string) Metric {
80+
return newValue(desc, UntypedValue, 0, lvs...)
81+
})
82+
return &vec
83+
}
84+
85+
func BenchmarkMetricVecWithLabelValuesBasic(B *testing.B) {
86+
benchmarkMetricVecWithLabelValues(B, map[string][]string{
87+
"l1": []string{"onevalue"},
88+
"l2": []string{"twovalue"},
89+
})
90+
}
91+
92+
func BenchmarkMetricVecWithLabelValues2Keys10ValueCardinality(B *testing.B) {
93+
benchmarkMetricVecWithLabelValuesCardinality(B, 2, 10)
94+
}
95+
96+
func BenchmarkMetricVecWithLabelValues4Keys10ValueCardinality(B *testing.B) {
97+
benchmarkMetricVecWithLabelValuesCardinality(B, 4, 10)
98+
}
99+
100+
func BenchmarkMetricVecWithLabelValues2Keys100ValueCardinality(B *testing.B) {
101+
benchmarkMetricVecWithLabelValuesCardinality(B, 2, 100)
102+
}
103+
104+
func BenchmarkMetricVecWithLabelValues10Keys100ValueCardinality(B *testing.B) {
105+
benchmarkMetricVecWithLabelValuesCardinality(B, 10, 100)
106+
}
107+
108+
func BenchmarkMetricVecWithLabelValues10Keys1000ValueCardinality(B *testing.B) {
109+
benchmarkMetricVecWithLabelValuesCardinality(B, 10, 1000)
110+
}
111+
112+
func benchmarkMetricVecWithLabelValuesCardinality(B *testing.B, nkeys, nvalues int) {
113+
labels := map[string][]string{}
114+
115+
for i := 0; i < nkeys; i++ {
116+
var (
117+
k = fmt.Sprintf("key-%v", i)
118+
vs = make([]string, 0, nvalues)
119+
)
120+
for j := 0; j < nvalues; j++ {
121+
vs = append(vs, fmt.Sprintf("value-%v", j))
122+
}
123+
labels[k] = vs
124+
}
125+
126+
benchmarkMetricVecWithLabelValues(B, labels)
127+
}
128+
129+
func benchmarkMetricVecWithLabelValues(B *testing.B, labels map[string][]string) {
130+
var keys []string
131+
for k := range labels { // map order dependent, who cares though
132+
keys = append(keys, k)
133+
}
134+
135+
values := make([]string, len(labels)) // value cache for permutations
136+
vec := newUntypedMetricVec("test", "helpless", keys)
137+
138+
B.ReportAllocs()
139+
B.ResetTimer()
140+
for i := 0; i < B.N; i++ {
141+
// varies input across provide map entries based on key size.
142+
for j, k := range keys {
143+
candidates := labels[k]
144+
values[j] = candidates[i%len(candidates)]
145+
}
146+
147+
vec.WithLabelValues(values...)
148+
}
149+
}

0 commit comments

Comments
 (0)