aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/metrics.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2020-08-06 19:04:46 +0000
committerMichael Knyszek <mknyszek@google.com>2020-10-26 21:47:43 +0000
commit8e2370bf7f0c992ce1ea5dc54b43551cea71a485 (patch)
treec82b9ded4145e6ecaa8813e31d00358b2cf2e793 /src/runtime/metrics.go
parentc305e49e96deafe54a8e43010ea76fead6da0a98 (diff)
downloadgo-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.go52
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