Inline hash/fnv.

This commit is contained in:
Robert Vollmert 2015-11-09 14:52:51 +01:00
parent 39a26f2e35
commit 1312da4c0c
9 changed files with 30 additions and 35 deletions

View File

@ -15,7 +15,6 @@ package prometheus
import ( import (
"errors" "errors"
"hash/fnv"
) )
// Counter is a Metric that represents a single numerical value that only ever // Counter is a Metric that represents a single numerical value that only ever
@ -97,7 +96,6 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
MetricVec: MetricVec{ MetricVec: MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
result := &counter{value: value{ result := &counter{value: value{
desc: desc, desc: desc,

22
prometheus/fnv.go Normal file
View File

@ -0,0 +1,22 @@
package prometheus
// Inline and byte-free variant of hash/fnv's fnv64a.
const (
offset64 = 14695981039346656037
prime64 = 1099511628211
)
// hashNew initializies a new fnv64a hash value.
func hashNew() uint64 {
return offset64
}
// hashAdd adds a string to a fnv64a hash value, returning the updated hash.
func hashAdd(h uint64, s string) uint64 {
for i := 0; i < len(s); i++ {
h ^= uint64(s[i])
h *= prime64
}
return h
}

View File

@ -13,8 +13,6 @@
package prometheus package prometheus
import "hash/fnv"
// Gauge is a Metric that represents a single numerical value that can // Gauge is a Metric that represents a single numerical value that can
// arbitrarily go up and down. // arbitrarily go up and down.
// //
@ -77,7 +75,6 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
MetricVec: MetricVec{ MetricVec: MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newValue(desc, GaugeValue, 0, lvs...) return newValue(desc, GaugeValue, 0, lvs...)
}, },

View File

@ -15,7 +15,6 @@ package prometheus
import ( import (
"fmt" "fmt"
"hash/fnv"
"math" "math"
"sort" "sort"
"sync/atomic" "sync/atomic"
@ -305,7 +304,6 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
MetricVec: MetricVec{ MetricVec: MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newHistogram(desc, opts, lvs...) return newHistogram(desc, opts, lvs...)
}, },

View File

@ -15,7 +15,6 @@ package prometheus
import ( import (
"fmt" "fmt"
"hash/fnv"
"math" "math"
"sort" "sort"
"sync" "sync"
@ -408,7 +407,6 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
MetricVec: MetricVec{ MetricVec: MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newSummary(desc, opts, lvs...) return newSummary(desc, opts, lvs...)
}, },

View File

@ -13,8 +13,6 @@
package prometheus package prometheus
import "hash/fnv"
// Untyped is a Metric that represents a single numerical value that can // Untyped is a Metric that represents a single numerical value that can
// arbitrarily go up and down. // arbitrarily go up and down.
// //
@ -75,7 +73,6 @@ func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
MetricVec: MetricVec{ MetricVec: MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...) return newValue(desc, UntypedValue, 0, lvs...)
}, },

View File

@ -14,9 +14,7 @@
package prometheus package prometheus
import ( import (
"bytes"
"fmt" "fmt"
"hash"
"sync" "sync"
) )
@ -26,16 +24,10 @@ import (
// type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already // type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already
// provided in this package. // provided in this package.
type MetricVec struct { type MetricVec struct {
mtx sync.RWMutex // Protects not only children, but also hash and buf. mtx sync.RWMutex // Protects the children.
children map[uint64]Metric children map[uint64]Metric
desc *Desc desc *Desc
// hash is our own hash instance to avoid repeated allocations.
hash hash.Hash64
// buf is used to copy string contents into it for hashing,
// again to avoid allocations.
buf bytes.Buffer
newMetric func(labelValues ...string) Metric newMetric func(labelValues ...string) Metric
} }
@ -208,30 +200,26 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
if len(vals) != len(m.desc.variableLabels) { if len(vals) != len(m.desc.variableLabels) {
return 0, errInconsistentCardinality return 0, errInconsistentCardinality
} }
m.hash.Reset() h := hashNew()
for _, val := range vals { for _, val := range vals {
m.buf.Reset() h = hashAdd(h, val)
m.buf.WriteString(val)
m.hash.Write(m.buf.Bytes())
} }
return m.hash.Sum64(), nil return h, nil
} }
func (m *MetricVec) hashLabels(labels Labels) (uint64, error) { func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
if len(labels) != len(m.desc.variableLabels) { if len(labels) != len(m.desc.variableLabels) {
return 0, errInconsistentCardinality return 0, errInconsistentCardinality
} }
m.hash.Reset() h := hashNew()
for _, label := range m.desc.variableLabels { for _, label := range m.desc.variableLabels {
val, ok := labels[label] val, ok := labels[label]
if !ok { if !ok {
return 0, fmt.Errorf("label name %q missing in label map", label) return 0, fmt.Errorf("label name %q missing in label map", label)
} }
m.buf.Reset() h = hashAdd(h, val)
m.buf.WriteString(val)
m.hash.Write(m.buf.Bytes())
} }
return m.hash.Sum64(), nil return h, nil
} }
func (m *MetricVec) getOrCreateMetric(hash uint64, labelValues ...string) Metric { func (m *MetricVec) getOrCreateMetric(hash uint64, labelValues ...string) Metric {

View File

@ -14,7 +14,6 @@
package prometheus package prometheus
import ( import (
"hash/fnv"
"testing" "testing"
) )
@ -23,7 +22,6 @@ func TestDelete(t *testing.T) {
vec := MetricVec{ vec := MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...) return newValue(desc, UntypedValue, 0, lvs...)
}, },
@ -63,7 +61,6 @@ func TestDeleteLabelValues(t *testing.T) {
vec := MetricVec{ vec := MetricVec{
children: map[uint64]Metric{}, children: map[uint64]Metric{},
desc: desc, desc: desc,
hash: fnv.New64a(),
newMetric: func(lvs ...string) Metric { newMetric: func(lvs ...string) Metric {
return newValue(desc, UntypedValue, 0, lvs...) return newValue(desc, UntypedValue, 0, lvs...)
}, },