1
0
mirror of https://github.com/golang/go synced 2024-11-27 01:51:23 -07:00

runtime: copy in MemStats fields explicitly

Currently MemStats is populated via an unsafe memmove from memstats, but
this places unnecessary structural restrictions on memstats, is annoying
to reason about, and tightly couples the two. Instead, just populate the
fields of MemStats explicitly.

Change-Id: I96f6a64326b1a91d4084e7b30169a4bbe6a331f9
Reviewed-on: https://go-review.googlesource.com/c/go/+/246972
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-07-31 21:32:26 +00:00 committed by Michael Knyszek
parent 8ebc58452a
commit 39e335ac06

View File

@ -12,8 +12,6 @@ import (
)
// Statistics.
// If you edit this structure, also edit type MemStats below.
// Their layouts must match exactly.
//
// For detailed descriptions see the documentation for MemStats.
// Fields that differ from MemStats are further documented here.
@ -87,8 +85,6 @@ type mstats struct {
// to 64 bits for atomic operations on 32 bit platforms.
_ [1 - _NumSizeClasses%2]uint32
// Statistics below here are not exported to MemStats directly.
last_gc_nanotime uint64 // last gc (monotonic time)
tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
last_next_gc uint64 // next_gc for the previous GC
@ -430,20 +426,7 @@ type MemStats struct {
}
}
// Size of the trailing by_size array differs between mstats and MemStats,
// and all data after by_size is local to runtime, not exported.
// NumSizeClasses was changed, but we cannot change MemStats because of backward compatibility.
// sizeof_C_MStats is the size of the prefix of mstats that
// corresponds to MemStats. It should match Sizeof(MemStats{}).
var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
func init() {
var memStats MemStats
if sizeof_C_MStats != unsafe.Sizeof(memStats) {
println(sizeof_C_MStats, unsafe.Sizeof(memStats))
throw("MStats vs MemStatsType size mismatch")
}
if unsafe.Offsetof(memstats.heap_live)%8 != 0 {
println(unsafe.Offsetof(memstats.heap_live))
throw("memstats.heap_live not aligned to 8 bytes")
@ -469,14 +452,55 @@ func ReadMemStats(m *MemStats) {
func readmemstats_m(stats *MemStats) {
updatememstats()
// The size of the trailing by_size array differs between
// mstats and MemStats. NumSizeClasses was changed, but we
// cannot change MemStats because of backward compatibility.
memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
stats.Alloc = memstats.alloc
stats.TotalAlloc = memstats.total_alloc
stats.Sys = memstats.sys
stats.Mallocs = memstats.nmalloc
stats.Frees = memstats.nfree
stats.HeapAlloc = memstats.heap_alloc
stats.HeapSys = memstats.heap_sys.load()
stats.HeapIdle = memstats.heap_idle
stats.HeapInuse = memstats.heap_inuse
stats.HeapReleased = memstats.heap_released
stats.HeapObjects = memstats.heap_objects
stats.StackInuse = memstats.stacks_inuse
// memstats.stacks_sys is only memory mapped directly for OS stacks.
// Add in heap-allocated stack memory for user consumption.
stats.StackSys += stats.StackInuse
stats.StackSys = memstats.stacks_inuse + memstats.stacks_sys.load()
stats.MSpanInuse = memstats.mspan_inuse
stats.MSpanSys = memstats.mspan_sys.load()
stats.MCacheInuse = memstats.mcache_inuse
stats.MCacheSys = memstats.mcache_sys.load()
stats.BuckHashSys = memstats.buckhash_sys.load()
stats.GCSys = memstats.gc_sys.load()
stats.OtherSys = memstats.other_sys.load()
stats.NextGC = memstats.next_gc
stats.LastGC = memstats.last_gc_unix
stats.PauseTotalNs = memstats.pause_total_ns
stats.PauseNs = memstats.pause_ns
stats.PauseEnd = memstats.pause_end
stats.NumGC = memstats.numgc
stats.NumForcedGC = memstats.numforcedgc
stats.GCCPUFraction = memstats.gc_cpu_fraction
stats.EnableGC = true
// Handle BySize. Copy N values, where N is
// the minimum of the lengths of the two arrays.
// Unfortunately copy() won't work here because
// the arrays have different structs.
//
// TODO(mknyszek): Consider renaming the fields
// of by_size's elements to align so we can use
// the copy built-in.
bySizeLen := len(stats.BySize)
if l := len(memstats.by_size); l < bySizeLen {
bySizeLen = l
}
for i := 0; i < bySizeLen; i++ {
stats.BySize[i].Size = memstats.by_size[i].size
stats.BySize[i].Mallocs = memstats.by_size[i].nmalloc
stats.BySize[i].Frees = memstats.by_size[i].nfree
}
}
//go:linkname readGCStats runtime/debug.readGCStats