Improve Gauge and Counter performance.
This is accomplished by using the functions from the atomic packages instead of a mutex. benchmark old ns/op new ns/op delta BenchmarkGaugeNoLabels-2 118 9.40 -92.03% BenchmarkGaugeNoLabels 117 9.38 -91.98% BenchmarkGaugeNoLabels-4 117 9.40 -91.97% BenchmarkCounterNoLabels-2 137 16.8 -87.74% BenchmarkCounterNoLabels 136 16.8 -87.65% BenchmarkCounterNoLabels-4 136 16.8 -87.65% BenchmarkGaugeWithLabelValues-4 400 279 -30.25% BenchmarkGaugeWithLabelValues-2 398 279 -29.90% BenchmarkGaugeWithLabelValues 400 283 -29.25% BenchmarkCounterWithLabelValues-4 397 286 -27.96% BenchmarkCounterWithLabelValues-2 396 286 -27.78% BenchmarkCounterWithLabelValues 394 285 -27.66% BenchmarkCounterWithPreparedMappedLabels 587 454 -22.66% BenchmarkCounterWithPreparedMappedLabels-2 581 456 -21.51% BenchmarkCounterWithPreparedMappedLabels-4 654 539 -17.58% BenchmarkCounterWithMappedLabels-2 1441 1218 -15.48% BenchmarkCounterWithMappedLabels 1099 963 -12.37% BenchmarkCounterWithMappedLabels-4 1636 1501 -8.25%
This commit is contained in:
parent
88b6ea5852
commit
4f73a8b017
|
@ -14,6 +14,7 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
@ -26,11 +27,11 @@ func TestCounterAdd(t *testing.T) {
|
||||||
ConstLabels: Labels{"a": "1", "b": "2"},
|
ConstLabels: Labels{"a": "1", "b": "2"},
|
||||||
}).(*counter)
|
}).(*counter)
|
||||||
counter.Inc()
|
counter.Inc()
|
||||||
if expected, got := 1., counter.val; expected != got {
|
if expected, got := 1., math.Float64frombits(counter.valBits); expected != got {
|
||||||
t.Errorf("Expected %f, got %f.", expected, got)
|
t.Errorf("Expected %f, got %f.", expected, got)
|
||||||
}
|
}
|
||||||
counter.Add(42)
|
counter.Add(42)
|
||||||
if expected, got := 43., counter.val; expected != got {
|
if expected, got := 43., math.Float64frombits(counter.valBits); expected != got {
|
||||||
t.Errorf("Expected %f, got %f.", expected, got)
|
t.Errorf("Expected %f, got %f.", expected, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ func TestGaugeConcurrency(t *testing.T) {
|
||||||
}
|
}
|
||||||
start.Done()
|
start.Done()
|
||||||
|
|
||||||
if expected, got := <-result, gge.(*value).val; math.Abs(expected-got) > 0.000001 {
|
if expected, got := <-result, math.Float64frombits(gge.(*value).valBits); math.Abs(expected-got) > 0.000001 {
|
||||||
t.Fatalf("expected approx. %f, got %f", expected, got)
|
t.Fatalf("expected approx. %f, got %f", expected, got)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ func TestGaugeVecConcurrency(t *testing.T) {
|
||||||
start.Done()
|
start.Done()
|
||||||
|
|
||||||
for i := range sStreams {
|
for i := range sStreams {
|
||||||
if expected, got := <-results[i], gge.WithLabelValues(string('A'+i)).(*value).val; math.Abs(expected-got) > 0.000001 {
|
if expected, got := <-results[i], math.Float64frombits(gge.WithLabelValues(string('A'+i)).(*value).valBits); math.Abs(expected-got) > 0.000001 {
|
||||||
t.Fatalf("expected approx. %f, got %f", expected, got)
|
t.Fatalf("expected approx. %f, got %f", expected, got)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,9 @@ package prometheus
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
|
@ -44,10 +45,9 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
||||||
type value struct {
|
type value struct {
|
||||||
SelfCollector
|
SelfCollector
|
||||||
|
|
||||||
mtx sync.RWMutex
|
|
||||||
desc *Desc
|
desc *Desc
|
||||||
valType ValueType
|
valType ValueType
|
||||||
val float64
|
valBits uint64 // These are the bits of the represented float64 value.
|
||||||
labelPairs []*dto.LabelPair
|
labelPairs []*dto.LabelPair
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...strin
|
||||||
result := &value{
|
result := &value{
|
||||||
desc: desc,
|
desc: desc,
|
||||||
valType: valueType,
|
valType: valueType,
|
||||||
val: val,
|
valBits: math.Float64bits(val),
|
||||||
labelPairs: makeLabelPairs(desc, labelValues),
|
labelPairs: makeLabelPairs(desc, labelValues),
|
||||||
}
|
}
|
||||||
result.Init(result)
|
result.Init(result)
|
||||||
|
@ -73,10 +73,7 @@ func (v *value) Desc() *Desc {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *value) Set(val float64) {
|
func (v *value) Set(val float64) {
|
||||||
v.mtx.Lock()
|
atomic.StoreUint64(&v.valBits, math.Float64bits(val))
|
||||||
defer v.mtx.Unlock()
|
|
||||||
|
|
||||||
v.val = val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *value) Inc() {
|
func (v *value) Inc() {
|
||||||
|
@ -88,10 +85,13 @@ func (v *value) Dec() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *value) Add(val float64) {
|
func (v *value) Add(val float64) {
|
||||||
v.mtx.Lock()
|
for {
|
||||||
defer v.mtx.Unlock()
|
oldBits := atomic.LoadUint64(&v.valBits)
|
||||||
|
newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
|
||||||
v.val += val
|
if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *value) Sub(val float64) {
|
func (v *value) Sub(val float64) {
|
||||||
|
@ -99,10 +99,7 @@ func (v *value) Sub(val float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *value) Write(out *dto.Metric) error {
|
func (v *value) Write(out *dto.Metric) error {
|
||||||
v.mtx.RLock()
|
val := math.Float64frombits(atomic.LoadUint64(&v.valBits))
|
||||||
val := v.val
|
|
||||||
v.mtx.RUnlock()
|
|
||||||
|
|
||||||
return populateMetric(v.valType, val, v.labelPairs, out)
|
return populateMetric(v.valType, val, v.labelPairs, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue