Allow a zero threshold of zero
Signed-off-by: beorn7 <beorn@grafana.com>
This commit is contained in:
parent
aa6f67a9e6
commit
9ef5f90a76
|
@ -538,8 +538,6 @@ func ExampleHistogram() {
|
||||||
// cumulative_count: 816
|
// cumulative_count: 816
|
||||||
// upper_bound: 40
|
// upper_bound: 40
|
||||||
// >
|
// >
|
||||||
// sb_schema: 0
|
|
||||||
// sb_zero_threshold: 0
|
|
||||||
// >
|
// >
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -369,8 +369,13 @@ type HistogramOpts struct {
|
||||||
// SparseBucketsZeroThreshold are accumulated into a “zero” bucket. For
|
// SparseBucketsZeroThreshold are accumulated into a “zero” bucket. For
|
||||||
// best results, this should be close to a bucket boundary. This is
|
// best results, this should be close to a bucket boundary. This is
|
||||||
// usually the case if picking a power of two. If
|
// usually the case if picking a power of two. If
|
||||||
// SparseBucketsZeroThreshold is left at zero (or set to a negative
|
// SparseBucketsZeroThreshold is left at zero,
|
||||||
// value), DefSparseBucketsZeroThreshold is used as the threshold.
|
// DefSparseBucketsZeroThreshold is used as the threshold. If it is set
|
||||||
|
// to a negative value, a threshold of zero is used, i.e. only
|
||||||
|
// observations of precisely zero will go into the zero
|
||||||
|
// bucket. (TODO(beorn7): That's obviously weird and just a consequence
|
||||||
|
// of making the zero value of HistogramOpts meaningful. Has to be
|
||||||
|
// solved more elegantly in the final version.)
|
||||||
SparseBucketsZeroThreshold float64
|
SparseBucketsZeroThreshold float64
|
||||||
// TODO(beorn7): Need a setting to limit total bucket count and to
|
// TODO(beorn7): Need a setting to limit total bucket count and to
|
||||||
// configure a strategy to enforce the limit, e.g. if minimum duration
|
// configure a strategy to enforce the limit, e.g. if minimum duration
|
||||||
|
@ -413,22 +418,24 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &histogram{
|
h := &histogram{
|
||||||
desc: desc,
|
desc: desc,
|
||||||
upperBounds: opts.Buckets,
|
upperBounds: opts.Buckets,
|
||||||
sparseThreshold: opts.SparseBucketsZeroThreshold,
|
labelPairs: MakeLabelPairs(desc, labelValues),
|
||||||
labelPairs: MakeLabelPairs(desc, labelValues),
|
counts: [2]*histogramCounts{{}, {}},
|
||||||
counts: [2]*histogramCounts{{}, {}},
|
now: time.Now,
|
||||||
now: time.Now,
|
|
||||||
}
|
}
|
||||||
if len(h.upperBounds) == 0 && opts.SparseBucketsFactor <= 1 {
|
if len(h.upperBounds) == 0 && opts.SparseBucketsFactor <= 1 {
|
||||||
h.upperBounds = DefBuckets
|
h.upperBounds = DefBuckets
|
||||||
}
|
}
|
||||||
if h.sparseThreshold <= 0 {
|
|
||||||
h.sparseThreshold = DefSparseBucketsZeroThreshold
|
|
||||||
}
|
|
||||||
if opts.SparseBucketsFactor <= 1 {
|
if opts.SparseBucketsFactor <= 1 {
|
||||||
h.sparseThreshold = 0 // To mark that there are no sparse buckets.
|
h.sparseSchema = math.MinInt32 // To mark that there are no sparse buckets.
|
||||||
} else {
|
} else {
|
||||||
|
switch {
|
||||||
|
case opts.SparseBucketsZeroThreshold > 0:
|
||||||
|
h.sparseThreshold = opts.SparseBucketsZeroThreshold
|
||||||
|
case opts.SparseBucketsZeroThreshold == 0:
|
||||||
|
h.sparseThreshold = DefSparseBucketsZeroThreshold
|
||||||
|
} // Leave h.sparseThreshold at 0 otherwise.
|
||||||
h.sparseSchema = pickSparseSchema(opts.SparseBucketsFactor)
|
h.sparseSchema = pickSparseSchema(opts.SparseBucketsFactor)
|
||||||
}
|
}
|
||||||
for i, upperBound := range h.upperBounds {
|
for i, upperBound := range h.upperBounds {
|
||||||
|
@ -559,8 +566,8 @@ type histogram struct {
|
||||||
upperBounds []float64
|
upperBounds []float64
|
||||||
labelPairs []*dto.LabelPair
|
labelPairs []*dto.LabelPair
|
||||||
exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar.
|
exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar.
|
||||||
sparseSchema int32
|
sparseSchema int32 // Set to math.MinInt32 if no sparse buckets are used.
|
||||||
sparseThreshold float64 // This is zero iff no sparse buckets are used.
|
sparseThreshold float64
|
||||||
|
|
||||||
now func() time.Time // To mock out time.Now() for testing.
|
now func() time.Time // To mock out time.Now() for testing.
|
||||||
}
|
}
|
||||||
|
@ -604,11 +611,9 @@ func (h *histogram) Write(out *dto.Metric) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
his := &dto.Histogram{
|
his := &dto.Histogram{
|
||||||
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
|
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
|
||||||
SampleCount: proto.Uint64(count),
|
SampleCount: proto.Uint64(count),
|
||||||
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
||||||
SbSchema: &h.sparseSchema,
|
|
||||||
SbZeroThreshold: &h.sparseThreshold,
|
|
||||||
}
|
}
|
||||||
out.Histogram = his
|
out.Histogram = his
|
||||||
out.Label = h.labelPairs
|
out.Label = h.labelPairs
|
||||||
|
@ -648,7 +653,9 @@ func (h *histogram) Write(out *dto.Metric) error {
|
||||||
atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i]))
|
atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i]))
|
||||||
atomic.StoreUint64(&coldCounts.buckets[i], 0)
|
atomic.StoreUint64(&coldCounts.buckets[i], 0)
|
||||||
}
|
}
|
||||||
if h.sparseThreshold != 0 {
|
if h.sparseSchema > math.MinInt32 {
|
||||||
|
his.SbZeroThreshold = &h.sparseThreshold
|
||||||
|
his.SbSchema = &h.sparseSchema
|
||||||
zeroBucket := atomic.LoadUint64(&coldCounts.sparseZeroBucket)
|
zeroBucket := atomic.LoadUint64(&coldCounts.sparseZeroBucket)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -749,7 +756,7 @@ func (h *histogram) findBucket(v float64) int {
|
||||||
// observe is the implementation for Observe without the findBucket part.
|
// observe is the implementation for Observe without the findBucket part.
|
||||||
func (h *histogram) observe(v float64, bucket int) {
|
func (h *histogram) observe(v float64, bucket int) {
|
||||||
// Do not add to sparse buckets for NaN observations.
|
// Do not add to sparse buckets for NaN observations.
|
||||||
doSparse := h.sparseThreshold != 0 && !math.IsNaN(v)
|
doSparse := h.sparseSchema > math.MinInt32 && !math.IsNaN(v)
|
||||||
var whichSparse, sparseKey int
|
var whichSparse, sparseKey int
|
||||||
if doSparse {
|
if doSparse {
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -470,7 +470,7 @@ func TestSparseHistogram(t *testing.T) {
|
||||||
name: "no sparse buckets",
|
name: "no sparse buckets",
|
||||||
observations: []float64{1, 2, 3},
|
observations: []float64{1, 2, 3},
|
||||||
factor: 1,
|
factor: 1,
|
||||||
want: `sample_count:3 sample_sum:6 bucket:<cumulative_count:0 upper_bound:0.005 > bucket:<cumulative_count:0 upper_bound:0.01 > bucket:<cumulative_count:0 upper_bound:0.025 > bucket:<cumulative_count:0 upper_bound:0.05 > bucket:<cumulative_count:0 upper_bound:0.1 > bucket:<cumulative_count:0 upper_bound:0.25 > bucket:<cumulative_count:0 upper_bound:0.5 > bucket:<cumulative_count:1 upper_bound:1 > bucket:<cumulative_count:2 upper_bound:2.5 > bucket:<cumulative_count:3 upper_bound:5 > bucket:<cumulative_count:3 upper_bound:10 > sb_schema:0 sb_zero_threshold:0 `, // Has conventional buckets because there are no sparse buckets.
|
want: `sample_count:3 sample_sum:6 bucket:<cumulative_count:0 upper_bound:0.005 > bucket:<cumulative_count:0 upper_bound:0.01 > bucket:<cumulative_count:0 upper_bound:0.025 > bucket:<cumulative_count:0 upper_bound:0.05 > bucket:<cumulative_count:0 upper_bound:0.1 > bucket:<cumulative_count:0 upper_bound:0.25 > bucket:<cumulative_count:0 upper_bound:0.5 > bucket:<cumulative_count:1 upper_bound:1 > bucket:<cumulative_count:2 upper_bound:2.5 > bucket:<cumulative_count:3 upper_bound:5 > bucket:<cumulative_count:3 upper_bound:10 > `, // Has conventional buckets because there are no sparse buckets.
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "factor 1.1 results in schema 3",
|
name: "factor 1.1 results in schema 3",
|
||||||
|
|
Loading…
Reference in New Issue