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
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
@ -26,11 +27,11 @@ func TestCounterAdd(t *testing.T) {
|
|||
ConstLabels: Labels{"a": "1", "b": "2"},
|
||||
}).(*counter)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ func TestGaugeConcurrency(t *testing.T) {
|
|||
}
|
||||
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)
|
||||
return false
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ func TestGaugeVecConcurrency(t *testing.T) {
|
|||
start.Done()
|
||||
|
||||
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)
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ package prometheus
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
|
@ -44,10 +45,9 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
|||
type value struct {
|
||||
SelfCollector
|
||||
|
||||
mtx sync.RWMutex
|
||||
desc *Desc
|
||||
valType ValueType
|
||||
val float64
|
||||
valBits uint64 // These are the bits of the represented float64 value.
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...strin
|
|||
result := &value{
|
||||
desc: desc,
|
||||
valType: valueType,
|
||||
val: val,
|
||||
valBits: math.Float64bits(val),
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}
|
||||
result.Init(result)
|
||||
|
@ -73,10 +73,7 @@ func (v *value) Desc() *Desc {
|
|||
}
|
||||
|
||||
func (v *value) Set(val float64) {
|
||||
v.mtx.Lock()
|
||||
defer v.mtx.Unlock()
|
||||
|
||||
v.val = val
|
||||
atomic.StoreUint64(&v.valBits, math.Float64bits(val))
|
||||
}
|
||||
|
||||
func (v *value) Inc() {
|
||||
|
@ -88,10 +85,13 @@ func (v *value) Dec() {
|
|||
}
|
||||
|
||||
func (v *value) Add(val float64) {
|
||||
v.mtx.Lock()
|
||||
defer v.mtx.Unlock()
|
||||
|
||||
v.val += val
|
||||
for {
|
||||
oldBits := atomic.LoadUint64(&v.valBits)
|
||||
newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
|
||||
if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *value) Sub(val float64) {
|
||||
|
@ -99,10 +99,7 @@ func (v *value) Sub(val float64) {
|
|||
}
|
||||
|
||||
func (v *value) Write(out *dto.Metric) error {
|
||||
v.mtx.RLock()
|
||||
val := v.val
|
||||
v.mtx.RUnlock()
|
||||
|
||||
val := math.Float64frombits(atomic.LoadUint64(&v.valBits))
|
||||
return populateMetric(v.valType, val, v.labelPairs, out)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue