Browse Source

Avoid copying of the COWMetric if we already have the metric available.

pull/545/head
beorn7 10 years ago
parent
commit
17443d288b
  1. 7
      rules/ast/functions.go
  2. 45
      rules/ast/quantile.go

7
rules/ast/functions.go

@ -514,12 +514,11 @@ func histogramQuantileImpl(timestamp clientmodel.Timestamp, args []Node) interfa
// TODO(beorn7): Issue a warning somehow.
continue
}
// TODO avoid copying each time by using a custom fingerprint
el.Metric.Delete(clientmodel.BucketLabel)
el.Metric.Delete(clientmodel.MetricNameLabel)
fp := el.Metric.Metric.Fingerprint()
fp := bucketFingerprint(el.Metric.Metric)
mb, ok := fpToMetricWithBuckets[fp]
if !ok {
el.Metric.Delete(clientmodel.BucketLabel)
el.Metric.Delete(clientmodel.MetricNameLabel)
mb = &metricWithBuckets{el.Metric, nil}
fpToMetricWithBuckets[fp] = mb
}

45
rules/ast/quantile.go

@ -14,6 +14,8 @@
package ast
import (
"encoding/binary"
"hash/fnv"
"math"
"sort"
@ -97,3 +99,46 @@ func quantile(q clientmodel.SampleValue, buckets buckets) float64 {
}
return bucketStart + (bucketEnd-bucketStart)*float64(rank/count)
}
// bucketFingerprint works like the Fingerprint method of Metric, but ignores
// the name and the bucket label.
func bucketFingerprint(m clientmodel.Metric) clientmodel.Fingerprint {
numLabels := 0
if len(m) > 2 {
numLabels = len(m) - 2
}
labelNames := make([]string, 0, numLabels)
maxLength := 0
for labelName, labelValue := range m {
if labelName == clientmodel.MetricNameLabel || labelName == clientmodel.BucketLabel {
continue
}
labelNames = append(labelNames, string(labelName))
if len(labelName) > maxLength {
maxLength = len(labelName)
}
if len(labelValue) > maxLength {
maxLength = len(labelValue)
}
}
sort.Strings(labelNames)
summer := fnv.New64a()
buf := make([]byte, maxLength)
for _, labelName := range labelNames {
labelValue := m[clientmodel.LabelName(labelName)]
copy(buf, labelName)
summer.Write(buf[:len(labelName)])
summer.Write([]byte{clientmodel.SeparatorByte})
copy(buf, labelValue)
summer.Write(buf[:len(labelValue)])
summer.Write([]byte{clientmodel.SeparatorByte})
}
return clientmodel.Fingerprint(binary.LittleEndian.Uint64(summer.Sum(nil)))
}

Loading…
Cancel
Save