runtime: implement dumpmemstats in terms of readmemstats_m

Since MemStats is now populated directly and some values are derived,
avoid duplicating the logic by instead populating the heap dump directly
from MemStats (external version) instead of memstats (runtime internal
version).

Change-Id: I0bec96bfa02d2ffd1b56475779c124a760e64238
Reviewed-on: https://go-review.googlesource.com/c/go/+/255817
Trust: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
Michael Anthony Knyszek 2020-09-17 21:19:28 +00:00 committed by Michael Knyszek
parent 80c6b92ecb
commit 32d0eaa44e
1 changed files with 44 additions and 32 deletions

View File

@ -20,8 +20,19 @@ import (
func runtime_debug_WriteHeapDump(fd uintptr) {
stopTheWorld("write heap dump")
// Keep m on this G's stack instead of the system stack.
// Both readmemstats_m and writeheapdump_m have pretty large
// peak stack depths and we risk blowing the system stack.
// This is safe because the world is stopped, so we don't
// need to worry about anyone shrinking and therefore moving
// our stack.
var m MemStats
systemstack(func() {
writeheapdump_m(fd)
// Call readmemstats_m here instead of deeper in
// writeheapdump_m because we might blow the system stack
// otherwise.
readmemstats_m(&m)
writeheapdump_m(fd, &m)
})
startTheWorld()
@ -539,39 +550,40 @@ func dumpms() {
}
}
func dumpmemstats() {
//go:systemstack
func dumpmemstats(m *MemStats) {
// These ints should be identical to the exported
// MemStats structure and should be ordered the same
// way too.
dumpint(tagMemStats)
dumpint(memstats.alloc)
dumpint(memstats.total_alloc)
dumpint(memstats.sys)
dumpint(memstats.nlookup)
dumpint(memstats.nmalloc)
dumpint(memstats.nfree)
dumpint(memstats.alloc)
dumpint(memstats.heap_sys.load())
dumpint(memstats.heap_sys.load() - memstats.heap_inuse)
dumpint(memstats.heap_inuse)
dumpint(memstats.heap_released)
dumpint(memstats.heap_objects)
dumpint(memstats.stacks_inuse)
dumpint(memstats.stacks_sys.load())
dumpint(memstats.mspan_inuse)
dumpint(memstats.mspan_sys.load())
dumpint(memstats.mcache_inuse)
dumpint(memstats.mcache_sys.load())
dumpint(memstats.buckhash_sys.load())
dumpint(memstats.gcMiscSys.load() + memstats.gcWorkBufInUse + memstats.gcProgPtrScalarBitsInUse)
dumpint(memstats.other_sys.load())
dumpint(memstats.next_gc)
dumpint(memstats.last_gc_unix)
dumpint(memstats.pause_total_ns)
dumpint(m.Alloc)
dumpint(m.TotalAlloc)
dumpint(m.Sys)
dumpint(m.Lookups)
dumpint(m.Mallocs)
dumpint(m.Frees)
dumpint(m.HeapAlloc)
dumpint(m.HeapSys)
dumpint(m.HeapIdle)
dumpint(m.HeapInuse)
dumpint(m.HeapReleased)
dumpint(m.HeapObjects)
dumpint(m.StackInuse)
dumpint(m.StackSys)
dumpint(m.MSpanInuse)
dumpint(m.MSpanSys)
dumpint(m.MCacheInuse)
dumpint(m.MCacheSys)
dumpint(m.BuckHashSys)
dumpint(m.GCSys)
dumpint(m.OtherSys)
dumpint(m.NextGC)
dumpint(m.LastGC)
dumpint(m.PauseTotalNs)
for i := 0; i < 256; i++ {
dumpint(memstats.pause_ns[i])
dumpint(m.PauseNs[i])
}
dumpint(uint64(memstats.numgc))
dumpint(uint64(m.NumGC))
}
func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs, frees uintptr) {
@ -642,7 +654,7 @@ func dumpmemprof() {
var dumphdr = []byte("go1.7 heap dump\n")
func mdump() {
func mdump(m *MemStats) {
// make sure we're done sweeping
for _, s := range mheap_.allspans {
if s.state.get() == mSpanInUse {
@ -657,13 +669,13 @@ func mdump() {
dumpgs()
dumpms()
dumproots()
dumpmemstats()
dumpmemstats(m)
dumpmemprof()
dumpint(tagEOF)
flush()
}
func writeheapdump_m(fd uintptr) {
func writeheapdump_m(fd uintptr, m *MemStats) {
_g_ := getg()
casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
_g_.waitreason = waitReasonDumpingHeap
@ -677,7 +689,7 @@ func writeheapdump_m(fd uintptr) {
dumpfd = fd
// Call dump routine.
mdump()
mdump(m)
// Reset dump file.
dumpfd = 0