aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/heapdump.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/heapdump.go')
-rw-r--r--libgo/go/runtime/heapdump.go98
1 files changed, 64 insertions, 34 deletions
diff --git a/libgo/go/runtime/heapdump.go b/libgo/go/runtime/heapdump.go
index 816d93c..f3f7382 100644
--- a/libgo/go/runtime/heapdump.go
+++ b/libgo/go/runtime/heapdump.go
@@ -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()
@@ -311,7 +322,10 @@ func finq_callback(fn *funcval, obj unsafe.Pointer, ft *functype, ot *ptrtype) {
}
func dumproots() {
- // MSpan.types
+ // To protect mheap_.allspans.
+ assertWorldStopped()
+
+ // mspan.types
for _, s := range mheap_.allspans {
if s.state.get() == mSpanInUse {
// Finalizers
@@ -335,6 +349,9 @@ func dumproots() {
var freemark [_PageSize / 8]bool
func dumpobjs() {
+ // To protect mheap_.allspans.
+ assertWorldStopped()
+
for _, s := range mheap_.allspans {
if s.state.get() != mSpanInUse {
continue
@@ -405,36 +422,42 @@ func dumpms() {
}
}
-func dumpmemstats() {
+//go:systemstack
+func dumpmemstats(m *MemStats) {
+ assertWorldStopped()
+
+ // 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.heap_alloc)
- dumpint(memstats.heap_sys)
- dumpint(memstats.heap_idle)
- dumpint(memstats.heap_inuse)
- dumpint(memstats.heap_released)
- dumpint(memstats.heap_objects)
- dumpint(memstats.stacks_inuse)
- dumpint(memstats.stacks_sys)
- dumpint(memstats.mspan_inuse)
- dumpint(memstats.mspan_sys)
- dumpint(memstats.mcache_inuse)
- dumpint(memstats.mcache_sys)
- dumpint(memstats.buckhash_sys)
- dumpint(memstats.gc_sys)
- dumpint(memstats.other_sys)
- 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) {
@@ -481,6 +504,9 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
}
func dumpmemprof() {
+ // To protect mheap_.allspans.
+ assertWorldStopped()
+
iterate_memprof(dumpmemprof_callback)
for _, s := range mheap_.allspans {
if s.state.get() != mSpanInUse {
@@ -501,7 +527,9 @@ func dumpmemprof() {
var dumphdr = []byte("go1.7 heap dump\n")
-func mdump() {
+func mdump(m *MemStats) {
+ assertWorldStopped()
+
// make sure we're done sweeping
for _, s := range mheap_.allspans {
if s.state.get() == mSpanInUse {
@@ -515,13 +543,15 @@ func mdump() {
dumpgs()
dumpms()
dumproots()
- dumpmemstats()
+ dumpmemstats(m)
dumpmemprof()
dumpint(tagEOF)
flush()
}
-func writeheapdump_m(fd uintptr) {
+func writeheapdump_m(fd uintptr, m *MemStats) {
+ assertWorldStopped()
+
_g_ := getg()
casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
_g_.waitreason = waitReasonDumpingHeap
@@ -535,7 +565,7 @@ func writeheapdump_m(fd uintptr) {
dumpfd = fd
// Call dump routine.
- mdump()
+ mdump(m)
// Reset dump file.
dumpfd = 0
@@ -574,7 +604,7 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector {
i := uintptr(0)
hbits := heapBitsForAddr(p)
for ; i < nptr; i++ {
- if i != 1 && !hbits.morePointers() {
+ if !hbits.morePointers() {
break // end of object
}
if hbits.isPointer() {