diff options
author | Michael Anthony Knyszek <mknyszek@google.com> | 2020-08-06 19:04:46 +0000 |
---|---|---|
committer | Michael Knyszek <mknyszek@google.com> | 2020-10-26 21:47:43 +0000 |
commit | 8e2370bf7f0c992ce1ea5dc54b43551cea71a485 (patch) | |
tree | c82b9ded4145e6ecaa8813e31d00358b2cf2e793 /src/runtime/metrics.go | |
parent | c305e49e96deafe54a8e43010ea76fead6da0a98 (diff) | |
download | go-8e2370bf7f0c992ce1ea5dc54b43551cea71a485.tar.gz go-8e2370bf7f0c992ce1ea5dc54b43551cea71a485.zip |
runtime,runtime/metrics: add object size distribution metrics
This change adds metrics for the distribution of objects allocated and
freed by size, mirroring MemStats' BySize field.
For #37112.
Change-Id: Ibaf1812da93598b37265ec97abc6669c1a5efcbf
Reviewed-on: https://go-review.googlesource.com/c/go/+/247045
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/metrics.go')
-rw-r--r-- | src/runtime/metrics.go | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/runtime/metrics.go b/src/runtime/metrics.go index 6595a4342c..32d8ab461c 100644 --- a/src/runtime/metrics.go +++ b/src/runtime/metrics.go @@ -18,6 +18,8 @@ var ( metricsSema uint32 = 1 metricsInit bool metrics map[string]metricData + + sizeClassBuckets []float64 ) type metricData struct { @@ -38,6 +40,10 @@ func initMetrics() { if metricsInit { return } + sizeClassBuckets = make([]float64, _NumSizeClasses) + for i := range sizeClassBuckets { + sizeClassBuckets[i] = float64(class_to_size[i]) + } metrics = map[string]metricData{ "/gc/cycles/automatic:gc-cycles": { deps: makeStatDepSet(sysStatsDep), @@ -60,6 +66,26 @@ func initMetrics() { out.scalar = in.sysStats.gcCyclesDone }, }, + "/gc/heap/allocs-by-size:objects": { + deps: makeStatDepSet(heapStatsDep), + compute: func(in *statAggregate, out *metricValue) { + hist := out.float64HistOrInit(sizeClassBuckets) + hist.counts[len(hist.counts)-1] = uint64(in.heapStats.largeAllocCount) + for i := range hist.buckets { + hist.counts[i] = uint64(in.heapStats.smallAllocCount[i]) + } + }, + }, + "/gc/heap/frees-by-size:objects": { + deps: makeStatDepSet(heapStatsDep), + compute: func(in *statAggregate, out *metricValue) { + hist := out.float64HistOrInit(sizeClassBuckets) + hist.counts[len(hist.counts)-1] = uint64(in.heapStats.largeFreeCount) + for i := range hist.buckets { + hist.counts[i] = uint64(in.heapStats.smallFreeCount[i]) + } + }, + }, "/gc/heap/goal:bytes": { deps: makeStatDepSet(sysStatsDep), compute: func(in *statAggregate, out *metricValue) { @@ -370,6 +396,32 @@ type metricValue struct { pointer unsafe.Pointer // contains non-scalar values. } +// float64HistOrInit tries to pull out an existing float64Histogram +// from the value, but if none exists, then it allocates one with +// the given buckets. +func (v *metricValue) float64HistOrInit(buckets []float64) *metricFloat64Histogram { + var hist *metricFloat64Histogram + if v.kind == metricKindFloat64Histogram && v.pointer != nil { + hist = (*metricFloat64Histogram)(v.pointer) + } else { + v.kind = metricKindFloat64Histogram + hist = new(metricFloat64Histogram) + v.pointer = unsafe.Pointer(hist) + } + hist.buckets = buckets + if len(hist.counts) != len(hist.buckets)+1 { + hist.counts = make([]uint64, len(buckets)+1) + } + return hist +} + +// metricFloat64Histogram is a runtime copy of runtime/metrics.Float64Histogram +// and must be kept structurally identical to that type. +type metricFloat64Histogram struct { + counts []uint64 + buckets []float64 +} + // agg is used by readMetrics, and is protected by metricsSema. // // Managed as a global variable because its pointer will be |