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>
This commit is contained in:
Michael Anthony Knyszek 2020-08-06 19:04:46 +00:00 committed by Michael Knyszek
parent c305e49e96
commit 8e2370bf7f
4 changed files with 104 additions and 0 deletions

View file

@ -98,6 +98,10 @@ func TestReadMetricsConsistency(t *testing.T) {
var totalVirtual struct {
got, want uint64
}
var objects struct {
alloc, free *metrics.Float64Histogram
total uint64
}
for i := range samples {
kind := samples[i].Value.Kind()
if want := descs[samples[i].Name].Kind; kind != want {
@ -118,11 +122,43 @@ func TestReadMetricsConsistency(t *testing.T) {
switch samples[i].Name {
case "/memory/classes/total:bytes":
totalVirtual.got = samples[i].Value.Uint64()
case "/gc/heap/objects:objects":
objects.total = samples[i].Value.Uint64()
case "/gc/heap/allocs-by-size:objects":
objects.alloc = samples[i].Value.Float64Histogram()
case "/gc/heap/frees-by-size:objects":
objects.free = samples[i].Value.Float64Histogram()
}
}
if totalVirtual.got != totalVirtual.want {
t.Errorf(`"/memory/classes/total:bytes" does not match sum of /memory/classes/**: got %d, want %d`, totalVirtual.got, totalVirtual.want)
}
if len(objects.alloc.Buckets) != len(objects.free.Buckets) {
t.Error("allocs-by-size and frees-by-size buckets don't match in length")
} else if len(objects.alloc.Counts) != len(objects.free.Counts) {
t.Error("allocs-by-size and frees-by-size counts don't match in length")
} else {
for i := range objects.alloc.Buckets {
ba := objects.alloc.Buckets[i]
bf := objects.free.Buckets[i]
if ba != bf {
t.Errorf("bucket %d is different for alloc and free hists: %f != %f", i, ba, bf)
}
}
if !t.Failed() {
got, want := uint64(0), objects.total
for i := range objects.alloc.Counts {
if objects.alloc.Counts[i] < objects.free.Counts[i] {
t.Errorf("found more allocs than frees in object dist bucket %d", i)
continue
}
got += objects.alloc.Counts[i] - objects.free.Counts[i]
}
if got != want {
t.Errorf("object distribution counts don't match count of live objects: got %d, want %d", got, want)
}
}
}
}
func BenchmarkReadMetricsLatency(b *testing.B) {