summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/histogram.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/histogram.go')
-rw-r--r--libgo/go/runtime/histogram.go60
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
}