diff options
author | Michael Anthony Knyszek <mknyszek@google.com> | 2021-01-06 23:05:22 +0000 |
---|---|---|
committer | Michael Knyszek <mknyszek@google.com> | 2021-01-08 03:43:44 +0000 |
commit | ae9771713383c1ee01a544cd50cfdbc22841380a (patch) | |
tree | b6cf30b25d9ce1123073ef103594ec7017a919eb /src/runtime/histogram.go | |
parent | a9ccd2d79574eead8c20d2bca4562cf2fd412787 (diff) | |
download | go-ae9771713383c1ee01a544cd50cfdbc22841380a.tar.gz go-ae9771713383c1ee01a544cd50cfdbc22841380a.zip |
runtime,runtime/metrics: use explicit histogram boundaries
This change modifies the semantics of
runtime/metrics.Float64Histogram.Buckets to remove implicit buckets to
that extend to positive and negative infinity and instead defines all
bucket boundaries as explicitly listed.
Bucket boundaries remain the same as before except
/gc/heap/allocs-by-size:objects and /gc/heap/frees-by-size:objects no
longer have a bucket that extends to negative infinity.
This change simplifies the Float64Histogram API, making it both easier
to understand and easier to use.
Also, add a test for allocs-by-size and frees-by-size that checks them
against MemStats.
Fixes #43443.
Change-Id: I5620f15bd084562dadf288f733c4a8cace21910c
Reviewed-on: https://go-review.googlesource.com/c/go/+/281238
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Trust: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/histogram.go')
-rw-r--r-- | src/runtime/histogram.go | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/src/runtime/histogram.go b/src/runtime/histogram.go index d48e856cd0..42baa6c5e2 100644 --- a/src/runtime/histogram.go +++ b/src/runtime/histogram.go @@ -7,6 +7,7 @@ package runtime import ( "runtime/internal/atomic" "runtime/internal/sys" + "unsafe" ) const ( @@ -69,7 +70,13 @@ const ( // for concurrent use. It is also safe to read all the values // atomically. type timeHistogram struct { - counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]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 } @@ -107,14 +114,30 @@ func (h *timeHistogram) record(duration int64) { 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 @@ -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 } |