diff options
Diffstat (limited to 'libgo/go/runtime/histogram.go')
-rw-r--r-- | libgo/go/runtime/histogram.go | 60 |
1 files changed, 42 insertions, 18 deletions
diff --git a/libgo/go/runtime/histogram.go b/libgo/go/runtime/histogram.go index 4020969eb99..42baa6c5e2c 100644 --- a/libgo/go/runtime/histogram.go +++ b/libgo/go/runtime/histogram.go @@ -7,6 +7,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "unsafe" ) const ( @@ -69,17 +70,21 @@ const ( // for concurrent use. It is also safe to read all the values // atomically. type timeHistogram struct { - counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]uint64 - overflow uint64 + counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]uint64 + + // underflow counts all the times we got a negative duration + // sample. Because of how time works on some platforms, it's + // possible to measure negative durations. We could ignore them, + // but we record them anyway because it's better to have some + // signal that it's happening than just missing samples. + underflow uint64 } // record adds the given duration to the distribution. -// -// Although the duration is an int64 to facilitate ease-of-use -// with e.g. nanotime, the duration must be non-negative. func (h *timeHistogram) record(duration int64) { if duration < 0 { - throw("timeHistogram encountered negative duration") + atomic.Xadd64(&h.underflow, 1) + return } // The index of the exponential bucket is just the index // of the highest set bit adjusted for how many bits we @@ -92,29 +97,47 @@ func (h *timeHistogram) record(duration int64) { superBucket = uint(sys.Len64(uint64(duration))) - timeHistSubBucketBits if superBucket*timeHistNumSubBuckets >= uint(len(h.counts)) { // The bucket index we got is larger than what we support, so - // add into the special overflow bucket. - atomic.Xadd64(&h.overflow, 1) - return + // include this count in the highest bucket, which extends to + // infinity. + superBucket = timeHistNumSuperBuckets - 1 + subBucket = timeHistNumSubBuckets - 1 + } else { + // The linear subbucket index is just the timeHistSubBucketsBits + // bits after the top bit. To extract that value, shift down + // the duration such that we leave the top bit and the next bits + // intact, then extract the index. + subBucket = uint((duration >> (superBucket - 1)) % timeHistNumSubBuckets) } - // The linear subbucket index is just the timeHistSubBucketsBits - // bits after the top bit. To extract that value, shift down - // the duration such that we leave the top bit and the next bits - // intact, then extract the index. - subBucket = uint((duration >> (superBucket - 1)) % timeHistNumSubBuckets) } else { subBucket = uint(duration) } atomic.Xadd64(&h.counts[superBucket*timeHistNumSubBuckets+subBucket], 1) } +const ( + fInf = 0x7FF0000000000000 + fNegInf = 0xFFF0000000000000 +) + +func float64Inf() float64 { + inf := uint64(fInf) + return *(*float64)(unsafe.Pointer(&inf)) +} + +func float64NegInf() float64 { + inf := uint64(fNegInf) + return *(*float64)(unsafe.Pointer(&inf)) +} + // timeHistogramMetricsBuckets generates a slice of boundaries for // the timeHistogram. These boundaries are represented in seconds, // not nanoseconds like the timeHistogram represents durations. func timeHistogramMetricsBuckets() []float64 { - b := make([]float64, timeHistTotalBuckets-1) + b := make([]float64, timeHistTotalBuckets+1) + b[0] = float64NegInf() for i := 0; i < timeHistNumSuperBuckets; i++ { superBucketMin := uint64(0) - // The (inclusive) minimum for the first bucket is 0. + // The (inclusive) minimum for the first non-negative bucket is 0. if i > 0 { // The minimum for the second bucket will be // 1 << timeHistSubBucketBits, indicating that all @@ -128,7 +151,7 @@ func timeHistogramMetricsBuckets() []float64 { // index to combine it with the bucketMin. subBucketShift := uint(0) if i > 1 { - // The first two buckets are exact with respect to integers, + // The first two super buckets are exact with respect to integers, // so we'll never have to shift the sub-bucket index. Thereafter, // we shift up by 1 with each subsequent bucket. subBucketShift = uint(i - 2) @@ -141,8 +164,9 @@ func timeHistogramMetricsBuckets() []float64 { // Convert the subBucketMin which is in nanoseconds to a float64 seconds value. // These values will all be exactly representable by a float64. - b[i*timeHistNumSubBuckets+j] = float64(subBucketMin) / 1e9 + b[i*timeHistNumSubBuckets+j+1] = float64(subBucketMin) / 1e9 } } + b[len(b)-1] = float64Inf() return b } |