runtime/metrics: add tiny allocs metric

Currently tiny allocations are not represented in either MemStats or
runtime/metrics, but they're represented in MemStats (indirectly) via
Mallocs. Add them to runtime/metrics by first merging
memstats.tinyallocs into consistentHeapStats (just for simplicity; it's
monotonic so metrics would still be self-consistent if we just read it
atomically) and then adding /gc/heap/tiny/allocs:objects to the list of
supported metrics.

Change-Id: Ie478006ab942a3e877b4a79065ffa43569722f3d
Reviewed-on: https://go-review.googlesource.com/c/go/+/312909
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
Michael Anthony Knyszek 2021-04-21 23:50:58 +00:00 committed by Michael Knyszek
parent 7d22c2181b
commit 0b9ca4d907
7 changed files with 64 additions and 13 deletions

View file

@ -40,6 +40,8 @@ func TestReadMetrics(t *testing.T) {
}
// Check to make sure the values we read line up with other values we read.
var allocsBySize *metrics.Float64Histogram
var tinyAllocs uint64
for i := range samples {
switch name := samples[i].Name; name {
case "/memory/classes/heap/free:bytes":
@ -84,6 +86,7 @@ func TestReadMetrics(t *testing.T) {
t.Errorf("histogram counts do not much BySize for class %d: got %d, want %d", i, c, m)
}
}
allocsBySize = hist
case "/gc/heap/frees-by-size:bytes":
hist := samples[i].Value.Float64Histogram()
// Skip size class 0 in BySize, because it's always empty and not represented
@ -95,9 +98,20 @@ func TestReadMetrics(t *testing.T) {
continue
}
if c, f := hist.Counts[i], sc.Frees; c != f {
t.Errorf("histogram counts do not much BySize for class %d: got %d, want %d", i, c, f)
t.Errorf("histogram counts do not match BySize for class %d: got %d, want %d", i, c, f)
}
}
case "/gc/heap/tiny/allocs:objects":
// Currently, MemStats adds tiny alloc count to both Mallocs AND Frees.
// The reason for this is because MemStats couldn't be extended at the time
// but there was a desire to have Mallocs at least be a little more representative,
// while having Mallocs - Frees still represent a live object count.
// Unfortunately, MemStats doesn't actually export a large allocation count,
// so it's impossible to pull this number out directly.
//
// Check tiny allocation count outside of this loop, by using the allocs-by-size
// histogram in order to figure out how many large objects there are.
tinyAllocs = samples[i].Value.Uint64()
case "/gc/heap/objects:objects":
checkUint64(t, name, samples[i].Value.Uint64(), mstats.HeapObjects)
case "/gc/heap/goal:bytes":
@ -110,6 +124,13 @@ func TestReadMetrics(t *testing.T) {
checkUint64(t, name, samples[i].Value.Uint64(), uint64(mstats.NumGC))
}
}
// Check tinyAllocs.
nonTinyAllocs := uint64(0)
for _, c := range allocsBySize.Counts {
nonTinyAllocs += c
}
checkUint64(t, "/gc/heap/tiny/allocs:objects", tinyAllocs, mstats.Mallocs-nonTinyAllocs)
}
func TestReadMetricsConsistency(t *testing.T) {