Skip to content

Commit 9ef5f90

Browse files
committed
Allow a zero threshold of zero
Signed-off-by: beorn7 <[email protected]>
1 parent aa6f67a commit 9ef5f90

File tree

3 files changed

+29
-24
lines changed

3 files changed

+29
-24
lines changed

prometheus/examples_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,6 @@ func ExampleHistogram() {
538538
// cumulative_count: 816
539539
// upper_bound: 40
540540
// >
541-
// sb_schema: 0
542-
// sb_zero_threshold: 0
543541
// >
544542
}
545543

prometheus/histogram.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,13 @@ type HistogramOpts struct {
369369
// SparseBucketsZeroThreshold are accumulated into a “zero” bucket. For
370370
// best results, this should be close to a bucket boundary. This is
371371
// usually the case if picking a power of two. If
372-
// SparseBucketsZeroThreshold is left at zero (or set to a negative
373-
// value), DefSparseBucketsZeroThreshold is used as the threshold.
372+
// SparseBucketsZeroThreshold is left at zero,
373+
// DefSparseBucketsZeroThreshold is used as the threshold. If it is set
374+
// to a negative value, a threshold of zero is used, i.e. only
375+
// observations of precisely zero will go into the zero
376+
// bucket. (TODO(beorn7): That's obviously weird and just a consequence
377+
// of making the zero value of HistogramOpts meaningful. Has to be
378+
// solved more elegantly in the final version.)
374379
SparseBucketsZeroThreshold float64
375380
// TODO(beorn7): Need a setting to limit total bucket count and to
376381
// 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
413418
}
414419

415420
h := &histogram{
416-
desc: desc,
417-
upperBounds: opts.Buckets,
418-
sparseThreshold: opts.SparseBucketsZeroThreshold,
419-
labelPairs: MakeLabelPairs(desc, labelValues),
420-
counts: [2]*histogramCounts{{}, {}},
421-
now: time.Now,
421+
desc: desc,
422+
upperBounds: opts.Buckets,
423+
labelPairs: MakeLabelPairs(desc, labelValues),
424+
counts: [2]*histogramCounts{{}, {}},
425+
now: time.Now,
422426
}
423427
if len(h.upperBounds) == 0 && opts.SparseBucketsFactor <= 1 {
424428
h.upperBounds = DefBuckets
425429
}
426-
if h.sparseThreshold <= 0 {
427-
h.sparseThreshold = DefSparseBucketsZeroThreshold
428-
}
429430
if opts.SparseBucketsFactor <= 1 {
430-
h.sparseThreshold = 0 // To mark that there are no sparse buckets.
431+
h.sparseSchema = math.MinInt32 // To mark that there are no sparse buckets.
431432
} else {
433+
switch {
434+
case opts.SparseBucketsZeroThreshold > 0:
435+
h.sparseThreshold = opts.SparseBucketsZeroThreshold
436+
case opts.SparseBucketsZeroThreshold == 0:
437+
h.sparseThreshold = DefSparseBucketsZeroThreshold
438+
} // Leave h.sparseThreshold at 0 otherwise.
432439
h.sparseSchema = pickSparseSchema(opts.SparseBucketsFactor)
433440
}
434441
for i, upperBound := range h.upperBounds {
@@ -559,8 +566,8 @@ type histogram struct {
559566
upperBounds []float64
560567
labelPairs []*dto.LabelPair
561568
exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar.
562-
sparseSchema int32
563-
sparseThreshold float64 // This is zero iff no sparse buckets are used.
569+
sparseSchema int32 // Set to math.MinInt32 if no sparse buckets are used.
570+
sparseThreshold float64
564571

565572
now func() time.Time // To mock out time.Now() for testing.
566573
}
@@ -604,11 +611,9 @@ func (h *histogram) Write(out *dto.Metric) error {
604611
}
605612

606613
his := &dto.Histogram{
607-
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
608-
SampleCount: proto.Uint64(count),
609-
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
610-
SbSchema: &h.sparseSchema,
611-
SbZeroThreshold: &h.sparseThreshold,
614+
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
615+
SampleCount: proto.Uint64(count),
616+
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
612617
}
613618
out.Histogram = his
614619
out.Label = h.labelPairs
@@ -648,7 +653,9 @@ func (h *histogram) Write(out *dto.Metric) error {
648653
atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i]))
649654
atomic.StoreUint64(&coldCounts.buckets[i], 0)
650655
}
651-
if h.sparseThreshold != 0 {
656+
if h.sparseSchema > math.MinInt32 {
657+
his.SbZeroThreshold = &h.sparseThreshold
658+
his.SbSchema = &h.sparseSchema
652659
zeroBucket := atomic.LoadUint64(&coldCounts.sparseZeroBucket)
653660

654661
defer func() {
@@ -749,7 +756,7 @@ func (h *histogram) findBucket(v float64) int {
749756
// observe is the implementation for Observe without the findBucket part.
750757
func (h *histogram) observe(v float64, bucket int) {
751758
// Do not add to sparse buckets for NaN observations.
752-
doSparse := h.sparseThreshold != 0 && !math.IsNaN(v)
759+
doSparse := h.sparseSchema > math.MinInt32 && !math.IsNaN(v)
753760
var whichSparse, sparseKey int
754761
if doSparse {
755762
switch {

prometheus/histogram_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ func TestSparseHistogram(t *testing.T) {
470470
name: "no sparse buckets",
471471
observations: []float64{1, 2, 3},
472472
factor: 1,
473-
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.
473+
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.
474474
},
475475
{
476476
name: "factor 1.1 results in schema 3",

0 commit comments

Comments
 (0)