Change histogram algorithm to comply with benchmark requirements
This commit is contained in:
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -75,10 +76,12 @@ func (v HistogramValue) String() string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Histogram accumulates values in the form of a histogram. The type of the
|
// A histograms is stored with exponentially increasing bucket sizes.
|
||||||
// values is int64, which is suitable for keeping track of things like RPC
|
// The first bucket is [0, m) where m = 1 + GrowthFactor
|
||||||
// latency in milliseconds. New histogram objects should be obtained via the
|
// Bucket n (n>=1) contains [m**n, m**(n+1))
|
||||||
// New() function.
|
// The type of the values is int64, which is suitable for keeping track
|
||||||
|
// of things like RPC latency in milliseconds.
|
||||||
|
//New histogram objects should be obtained via the New() function.
|
||||||
type Histogram struct {
|
type Histogram struct {
|
||||||
opts HistogramOptions
|
opts HistogramOptions
|
||||||
buckets []bucketInternal
|
buckets []bucketInternal
|
||||||
@ -95,9 +98,6 @@ type HistogramOptions struct {
|
|||||||
// GrowthFactor is the growth factor of the buckets. A value of 0.1
|
// GrowthFactor is the growth factor of the buckets. A value of 0.1
|
||||||
// indicates that bucket N+1 will be 10% larger than bucket N.
|
// indicates that bucket N+1 will be 10% larger than bucket N.
|
||||||
GrowthFactor float64
|
GrowthFactor float64
|
||||||
// SmallestBucketSize is the size of the first bucket. Bucket sizes are
|
|
||||||
// rounded down to the nearest integer.
|
|
||||||
SmallestBucketSize float64
|
|
||||||
// MinValue is the lower bound of the first bucket.
|
// MinValue is the lower bound of the first bucket.
|
||||||
MinValue int64
|
MinValue int64
|
||||||
}
|
}
|
||||||
@ -115,9 +115,6 @@ func NewHistogram(opts HistogramOptions) *Histogram {
|
|||||||
if opts.NumBuckets == 0 {
|
if opts.NumBuckets == 0 {
|
||||||
opts.NumBuckets = 32
|
opts.NumBuckets = 32
|
||||||
}
|
}
|
||||||
if opts.SmallestBucketSize == 0.0 {
|
|
||||||
opts.SmallestBucketSize = 1.0
|
|
||||||
}
|
|
||||||
h := Histogram{
|
h := Histogram{
|
||||||
opts: opts,
|
opts: opts,
|
||||||
buckets: make([]bucketInternal, opts.NumBuckets),
|
buckets: make([]bucketInternal, opts.NumBuckets),
|
||||||
@ -126,12 +123,14 @@ func NewHistogram(opts HistogramOptions) *Histogram {
|
|||||||
sumOfSquares: newCounter(),
|
sumOfSquares: newCounter(),
|
||||||
tracker: newTracker(),
|
tracker: newTracker(),
|
||||||
}
|
}
|
||||||
low := opts.MinValue
|
delta := 1.0
|
||||||
delta := opts.SmallestBucketSize
|
|
||||||
for i := 0; i < opts.NumBuckets; i++ {
|
for i := 0; i < opts.NumBuckets; i++ {
|
||||||
h.buckets[i].lowBound = float64(low)
|
if i == 0 {
|
||||||
|
h.buckets[i].lowBound = float64(opts.MinValue)
|
||||||
|
} else {
|
||||||
|
h.buckets[i].lowBound = float64(opts.MinValue) + delta
|
||||||
|
}
|
||||||
h.buckets[i].count = newCounter()
|
h.buckets[i].count = newCounter()
|
||||||
low = low + int64(delta)
|
|
||||||
delta = delta * (1.0 + opts.GrowthFactor)
|
delta = delta * (1.0 + opts.GrowthFactor)
|
||||||
}
|
}
|
||||||
return &h
|
return &h
|
||||||
@ -247,18 +246,15 @@ func (h *Histogram) Delta1m() HistogramValue {
|
|||||||
|
|
||||||
// findBucket does a binary search to find in which bucket the value goes.
|
// findBucket does a binary search to find in which bucket the value goes.
|
||||||
func (h *Histogram) findBucket(value int64) (int, error) {
|
func (h *Histogram) findBucket(value int64) (int, error) {
|
||||||
lastBucket := len(h.buckets) - 1
|
deltaValue := float64(value - h.opts.MinValue)
|
||||||
min, max := 0, lastBucket
|
var b int
|
||||||
for max >= min {
|
if deltaValue < 1 {
|
||||||
b := (min + max) / 2
|
b = 0
|
||||||
if float64(value) >= h.buckets[b].lowBound && (b == lastBucket || float64(value) < h.buckets[b+1].lowBound) {
|
} else {
|
||||||
return b, nil
|
b = int(math.Log(deltaValue) / math.Log(1+h.opts.GrowthFactor))
|
||||||
}
|
|
||||||
if float64(value) < h.buckets[b].lowBound {
|
|
||||||
max = b - 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
min = b + 1
|
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("no bucket for value: %d", value)
|
if b >= len(h.buckets) {
|
||||||
|
return 0, fmt.Errorf("no bucket for value: %d", value)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,9 @@ func (stats *Stats) maybeUpdate() {
|
|||||||
}
|
}
|
||||||
stats.histogram = NewHistogram(HistogramOptions{
|
stats.histogram = NewHistogram(HistogramOptions{
|
||||||
NumBuckets: numBuckets,
|
NumBuckets: numBuckets,
|
||||||
// max(i.e., Nth lower bound) = min + (1 + growthFactor)^(numBuckets-2).
|
// max-min+1(i.e., Nth upper bound, excluded) = (1 + growthFactor)^numBuckets.
|
||||||
GrowthFactor: math.Pow(float64(stats.max-stats.min), 1/float64(stats.numBuckets-2)) - 1,
|
GrowthFactor: math.Pow(float64(stats.max-stats.min+1), 1/float64(numBuckets)) - 1,
|
||||||
SmallestBucketSize: 1.0,
|
MinValue: stats.min})
|
||||||
MinValue: stats.min})
|
|
||||||
|
|
||||||
for _, d := range stats.durations {
|
for _, d := range stats.durations {
|
||||||
stats.histogram.Add(int64(d / stats.unit))
|
stats.histogram.Add(int64(d / stats.unit))
|
||||||
|
Reference in New Issue
Block a user