benchmark: measure label resolution in MetricVec

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2016-08-10 20:03:15 -07:00
parent 25db044749
commit c4004ef5f6
No known key found for this signature in database
GPG Key ID: FB5F6B2905D7ECF3
7 changed files with 108 additions and 57 deletions

View File

@ -96,10 +96,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
opts.ConstLabels, opts.ConstLabels,
) )
return &CounterVec{ return &CounterVec{
MetricVec: MetricVec{ MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
result := &counter{value: value{ result := &counter{value: value{
desc: desc, desc: desc,
valType: CounterValue, valType: CounterValue,
@ -107,8 +104,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
}} }}
result.init(result) // Init self-collection. result.init(result) // Init self-collection.
return result return result
}, }),
},
} }
} }

View File

@ -72,13 +72,9 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
opts.ConstLabels, opts.ConstLabels,
) )
return &GaugeVec{ return &GaugeVec{
MetricVec: MetricVec{ MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newValue(desc, GaugeValue, 0, lvs...) return newValue(desc, GaugeValue, 0, lvs...)
}, }),
},
} }
} }

View File

@ -301,13 +301,9 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
opts.ConstLabels, opts.ConstLabels,
) )
return &HistogramVec{ return &HistogramVec{
MetricVec: MetricVec{ MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newHistogram(desc, opts, lvs...) return newHistogram(desc, opts, lvs...)
}, }),
},
} }
} }

View File

@ -404,13 +404,9 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
opts.ConstLabels, opts.ConstLabels,
) )
return &SummaryVec{ return &SummaryVec{
MetricVec: MetricVec{ MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newSummary(desc, opts, lvs...) return newSummary(desc, opts, lvs...)
}, }),
},
} }
} }

View File

@ -70,13 +70,9 @@ func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
opts.ConstLabels, opts.ConstLabels,
) )
return &UntypedVec{ return &UntypedVec{
MetricVec: MetricVec{ MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...) return newValue(desc, UntypedValue, 0, lvs...)
}, }),
},
} }
} }

View File

@ -31,6 +31,16 @@ type MetricVec struct {
newMetric func(labelValues ...string) Metric newMetric func(labelValues ...string) Metric
} }
// newMetricVec returns an initialized MetricVec. The concrete value is
// returned for embedding into another struct.
func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) MetricVec {
return MetricVec{
children: map[uint64]Metric{},
desc: desc,
newMetric: newMetric,
}
}
// Describe implements Collector. The length of the returned slice // Describe implements Collector. The length of the returned slice
// is always one. // is always one.
func (m *MetricVec) Describe(ch chan<- *Desc) { func (m *MetricVec) Describe(ch chan<- *Desc) {

View File

@ -14,18 +14,12 @@
package prometheus package prometheus
import ( import (
"fmt"
"testing" "testing"
) )
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil) vec := newUntypedMetricVec("test", "helpless", []string{"l1", "l2"})
vec := MetricVec{
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...)
},
}
if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want { if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want {
t.Errorf("got %v, want %v", got, want) t.Errorf("got %v, want %v", got, want)
@ -57,14 +51,7 @@ func TestDelete(t *testing.T) {
} }
func TestDeleteLabelValues(t *testing.T) { func TestDeleteLabelValues(t *testing.T) {
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil) vec := newUntypedMetricVec("test", "helpless", []string{"l1", "l2"})
vec := MetricVec{
children: map[uint64]Metric{},
desc: desc,
newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...)
},
}
if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want { if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want {
t.Errorf("got %v, want %v", got, want) t.Errorf("got %v, want %v", got, want)
@ -86,3 +73,77 @@ func TestDeleteLabelValues(t *testing.T) {
t.Errorf("got %v, want %v", got, want) t.Errorf("got %v, want %v", got, want)
} }
} }
func newUntypedMetricVec(name, help string, labels []string) *MetricVec {
desc := NewDesc("test", "helpless", labels, nil)
vec := newMetricVec(desc, func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...)
})
return &vec
}
func BenchmarkMetricVecWithLabelValuesBasic(B *testing.B) {
benchmarkMetricVecWithLabelValues(B, map[string][]string{
"l1": []string{"onevalue"},
"l2": []string{"twovalue"},
})
}
func BenchmarkMetricVecWithLabelValues2Keys10ValueCardinality(B *testing.B) {
benchmarkMetricVecWithLabelValuesCardinality(B, 2, 10)
}
func BenchmarkMetricVecWithLabelValues4Keys10ValueCardinality(B *testing.B) {
benchmarkMetricVecWithLabelValuesCardinality(B, 4, 10)
}
func BenchmarkMetricVecWithLabelValues2Keys100ValueCardinality(B *testing.B) {
benchmarkMetricVecWithLabelValuesCardinality(B, 2, 100)
}
func BenchmarkMetricVecWithLabelValues10Keys100ValueCardinality(B *testing.B) {
benchmarkMetricVecWithLabelValuesCardinality(B, 10, 100)
}
func BenchmarkMetricVecWithLabelValues10Keys1000ValueCardinality(B *testing.B) {
benchmarkMetricVecWithLabelValuesCardinality(B, 10, 1000)
}
func benchmarkMetricVecWithLabelValuesCardinality(B *testing.B, nkeys, nvalues int) {
labels := map[string][]string{}
for i := 0; i < nkeys; i++ {
var (
k = fmt.Sprintf("key-%v", i)
vs = make([]string, 0, nvalues)
)
for j := 0; j < nvalues; j++ {
vs = append(vs, fmt.Sprintf("value-%v", j))
}
labels[k] = vs
}
benchmarkMetricVecWithLabelValues(B, labels)
}
func benchmarkMetricVecWithLabelValues(B *testing.B, labels map[string][]string) {
var keys []string
for k := range labels { // map order dependent, who cares though
keys = append(keys, k)
}
values := make([]string, len(labels)) // value cache for permutations
vec := newUntypedMetricVec("test", "helpless", keys)
B.ReportAllocs()
B.ResetTimer()
for i := 0; i < B.N; i++ {
// varies input across provide map entries based on key size.
for j, k := range keys {
candidates := labels[k]
values[j] = candidates[i%len(candidates)]
}
vec.WithLabelValues(values...)
}
}