package runtime
import (
)
func ( uintptr) {
stopTheWorld("write heap dump")
var MemStats
systemstack(func() {
readmemstats_m(&)
writeheapdump_m(, &)
})
startTheWorld()
}
const (
fieldKindEol = 0
fieldKindPtr = 1
fieldKindIface = 2
fieldKindEface = 3
tagEOF = 0
tagObject = 1
tagOtherRoot = 2
tagType = 3
tagGoroutine = 4
tagStackFrame = 5
tagParams = 6
tagFinalizer = 7
tagItab = 8
tagOSThread = 9
tagMemStats = 10
tagQueuedFinalizer = 11
tagData = 12
tagBSS = 13
tagDefer = 14
tagPanic = 15
tagMemProf = 16
tagAllocSample = 17
)
var dumpfd uintptr
var tmpbuf []byte
const (
bufSize = 4096
)
var buf [bufSize]byte
var nbuf uintptr
func ( unsafe.Pointer, uintptr) {
if == 0 {
return
}
if nbuf+ <= bufSize {
copy(buf[nbuf:], (*[bufSize]byte)()[:])
nbuf +=
return
}
write(dumpfd, unsafe.Pointer(&buf), int32(nbuf))
if >= bufSize {
write(dumpfd, , int32())
nbuf = 0
} else {
copy(buf[:], (*[bufSize]byte)()[:])
nbuf =
}
}
func ( byte) {
dwrite(unsafe.Pointer(&), 1)
}
func () {
write(dumpfd, unsafe.Pointer(&buf), int32(nbuf))
nbuf = 0
}
const (
typeCacheBuckets = 256
typeCacheAssoc = 4
)
type typeCacheBucket struct {
t [typeCacheAssoc]*_type
}
var typecache [typeCacheBuckets]typeCacheBucket
func ( uint64) {
var [10]byte
var int
for >= 0x80 {
[] = byte( | 0x80)
++
>>= 7
}
[] = byte()
++
dwrite(unsafe.Pointer(&), uintptr())
}
func ( bool) {
if {
dumpint(1)
} else {
dumpint(0)
}
}
func ( unsafe.Pointer, uintptr) {
dumpint(uint64())
dwrite(, )
}
func ( []byte) {
dumpint(uint64(len()))
if len() > 0 {
dwrite(unsafe.Pointer(&[0]), uintptr(len()))
}
}
func ( string) {
:= stringStructOf(&)
dumpmemrange(.str, uintptr(.len))
}
func ( *_type) {
if == nil {
return
}
:= &typecache[.hash&(typeCacheBuckets-1)]
if == .t[0] {
return
}
for := 1; < typeCacheAssoc; ++ {
if == .t[] {
for := ; > 0; -- {
.t[] = .t[-1]
}
.t[0] =
return
}
}
for := typeCacheAssoc - 1; > 0; -- {
.t[] = .t[-1]
}
.t[0] =
dumpint(tagType)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(.size))
if := .uncommon(); == nil || .nameOff(.pkgpath).name() == "" {
dumpstr(.string())
} else {
:= .nameOff(.pkgpath).name()
:= stringStructOf(&)
:= .name()
:= stringStructOf(&)
dumpint(uint64(uintptr(.len) + 1 + uintptr(.len)))
dwrite(.str, uintptr(.len))
dwritebyte('.')
dwrite(.str, uintptr(.len))
}
dumpbool(.kind&kindDirectIface == 0 || .ptrdata != 0)
}
func ( unsafe.Pointer, uintptr, bitvector) {
dumpint(tagObject)
dumpint(uint64(uintptr()))
dumpmemrange(, )
dumpfields()
}
func ( string, unsafe.Pointer) {
dumpint(tagOtherRoot)
dumpstr()
dumpint(uint64(uintptr()))
}
func ( unsafe.Pointer, *funcval, *_type, *ptrtype) {
dumpint(tagFinalizer)
dumpint(uint64(uintptr()))
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer(.fn))))
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer())))
}
type childInfo struct {
argoff uintptr
arglen uintptr
args bitvector
sp *uint8
depth uintptr
}
func ( *bitvector, uintptr) {
for := uintptr(0); < uintptr(.n); ++ {
if .ptrbit() == 1 {
dumpint(fieldKindPtr)
dumpint(uint64( + *sys.PtrSize))
}
}
}
func ( *stkframe, unsafe.Pointer) bool {
:= (*childInfo)()
:= .fn
:= .pc
:= int32(-1)
if != .entry {
--
= pcdatavalue(, _PCDATA_StackMapIndex, , nil)
}
if == -1 {
= 0
}
:= (*stackmap)(funcdata(, _FUNCDATA_LocalsPointerMaps))
var bitvector
if != nil && .n > 0 {
= stackmapdata(, )
} else {
.n = -1
}
dumpint(tagStackFrame)
dumpint(uint64(.sp))
dumpint(uint64(.depth))
dumpint(uint64(uintptr(unsafe.Pointer(.sp))))
dumpmemrange(unsafe.Pointer(.sp), .fp-.sp)
dumpint(uint64(.entry))
dumpint(uint64(.pc))
dumpint(uint64(.continpc))
:= funcname()
if == "" {
= "unknown function"
}
dumpstr()
if .args.n >= 0 {
dumpbv(&.args, .argoff)
} else {
for := .argoff; < .argoff+.arglen; += sys.PtrSize {
dumpint(fieldKindPtr)
dumpint(uint64())
}
}
if == nil {
for := .arglen; < .varp-.sp; += sys.PtrSize {
dumpint(fieldKindPtr)
dumpint(uint64())
}
} else if .n < 0 {
:= uintptr(-.n)
for := .varp - - .sp; < .varp-.sp; += sys.PtrSize {
dumpint(fieldKindPtr)
dumpint(uint64())
}
} else if .n > 0 {
dumpbv(&, .varp-uintptr(.n)*sys.PtrSize-.sp)
}
dumpint(fieldKindEol)
.argoff = .argp - .fp
.arglen = .arglen
.sp = (*uint8)(unsafe.Pointer(.sp))
.depth++
= (*stackmap)(funcdata(, _FUNCDATA_ArgsPointerMaps))
if != nil {
.args = stackmapdata(, )
} else {
.args.n = -1
}
return true
}
func ( *g) {
var , , uintptr
if .syscallsp != 0 {
= .syscallsp
= .syscallpc
= 0
} else {
= .sched.sp
= .sched.pc
= .sched.lr
}
dumpint(tagGoroutine)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64())
dumpint(uint64(.goid))
dumpint(uint64(.gopc))
dumpint(uint64(readgstatus()))
dumpbool(isSystemGoroutine(, false))
dumpbool(false)
dumpint(uint64(.waitsince))
dumpstr(.waitreason.String())
dumpint(uint64(uintptr(.sched.ctxt)))
dumpint(uint64(uintptr(unsafe.Pointer(.m))))
dumpint(uint64(uintptr(unsafe.Pointer(._defer))))
dumpint(uint64(uintptr(unsafe.Pointer(._panic))))
var childInfo
.args.n = -1
.arglen = 0
.sp = nil
.depth = 0
gentraceback(, , , , 0, nil, 0x7fffffff, dumpframe, noescape(unsafe.Pointer(&)), 0)
for := ._defer; != nil; = .link {
dumpint(tagDefer)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(.sp))
dumpint(uint64(.pc))
dumpint(uint64(uintptr(unsafe.Pointer(.fn))))
if .fn == nil {
dumpint(uint64(0))
} else {
dumpint(uint64(uintptr(unsafe.Pointer(.fn.fn))))
}
dumpint(uint64(uintptr(unsafe.Pointer(.link))))
}
for := ._panic; != nil; = .link {
dumpint(tagPanic)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer())))
:= efaceOf(&.arg)
dumpint(uint64(uintptr(unsafe.Pointer(._type))))
dumpint(uint64(uintptr(unsafe.Pointer(.data))))
dumpint(0)
dumpint(uint64(uintptr(unsafe.Pointer(.link))))
}
}
func () {
for := 0; uintptr() < allglen; ++ {
:= allgs[]
:= readgstatus()
switch {
default:
print("runtime: unexpected G.status ", hex(), "\n")
throw("dumpgs in STW - bad status")
case _Gdead:
case _Grunnable,
_Gsyscall,
_Gwaiting:
dumpgoroutine()
}
}
}
func ( *funcval, unsafe.Pointer, uintptr, *_type, *ptrtype) {
dumpint(tagQueuedFinalizer)
dumpint(uint64(uintptr()))
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer(.fn))))
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer())))
}
func () {
assertWorldStopped()
dumpint(tagData)
dumpint(uint64(firstmoduledata.data))
dumpmemrange(unsafe.Pointer(firstmoduledata.data), firstmoduledata.edata-firstmoduledata.data)
dumpfields(firstmoduledata.gcdatamask)
dumpint(tagBSS)
dumpint(uint64(firstmoduledata.bss))
dumpmemrange(unsafe.Pointer(firstmoduledata.bss), firstmoduledata.ebss-firstmoduledata.bss)
dumpfields(firstmoduledata.gcbssmask)
for , := range mheap_.allspans {
if .state.get() == mSpanInUse {
for := .specials; != nil; = .next {
if .kind != _KindSpecialFinalizer {
continue
}
:= (*specialfinalizer)(unsafe.Pointer())
:= unsafe.Pointer(.base() + uintptr(.special.offset))
dumpfinalizer(, .fn, .fint, .ot)
}
}
}
iterate_finq(finq_callback)
}
var freemark [_PageSize / 8]bool
func () {
assertWorldStopped()
for , := range mheap_.allspans {
if .state.get() != mSpanInUse {
continue
}
:= .base()
:= .elemsize
:= (.npages << _PageShift) /
if > uintptr(len(freemark)) {
throw("freemark array doesn't have enough entries")
}
for := uintptr(0); < .nelems; ++ {
if .isFree() {
freemark[] = true
}
}
for := uintptr(0); < ; , = +1, + {
if freemark[] {
freemark[] = false
continue
}
dumpobj(unsafe.Pointer(), , makeheapobjbv(, ))
}
}
}
func () {
dumpint(tagParams)
:= uintptr(1)
if *(*byte)(unsafe.Pointer(&)) == 1 {
dumpbool(false)
} else {
dumpbool(true)
}
dumpint(sys.PtrSize)
var , uintptr
for := range mheap_.arenas {
if mheap_.arenas[] == nil {
continue
}
for , := range mheap_.arenas[] {
if == nil {
continue
}
:= arenaBase(arenaIdx()<<arenaL1Shift | arenaIdx())
if == 0 || < {
=
}
if +heapArenaBytes > {
= + heapArenaBytes
}
}
}
dumpint(uint64())
dumpint(uint64())
dumpstr(sys.GOARCH)
dumpstr(sys.Goexperiment)
dumpint(uint64(ncpu))
}
func ( *itab) {
:= ._type
dumptype()
dumpint(tagItab)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(uintptr(unsafe.Pointer())))
}
func () {
iterate_itabs(itab_callback)
}
func () {
for := allm; != nil; = .alllink {
dumpint(tagOSThread)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64(.id))
dumpint(.procid)
}
}
func ( *MemStats) {
assertWorldStopped()
dumpint(tagMemStats)
dumpint(.Alloc)
dumpint(.TotalAlloc)
dumpint(.Sys)
dumpint(.Lookups)
dumpint(.Mallocs)
dumpint(.Frees)
dumpint(.HeapAlloc)
dumpint(.HeapSys)
dumpint(.HeapIdle)
dumpint(.HeapInuse)
dumpint(.HeapReleased)
dumpint(.HeapObjects)
dumpint(.StackInuse)
dumpint(.StackSys)
dumpint(.MSpanInuse)
dumpint(.MSpanSys)
dumpint(.MCacheInuse)
dumpint(.MCacheSys)
dumpint(.BuckHashSys)
dumpint(.GCSys)
dumpint(.OtherSys)
dumpint(.NextGC)
dumpint(.LastGC)
dumpint(.PauseTotalNs)
for := 0; < 256; ++ {
dumpint(.PauseNs[])
}
dumpint(uint64(.NumGC))
}
func ( *bucket, uintptr, *uintptr, , , uintptr) {
:= (*[100000]uintptr)(unsafe.Pointer())
dumpint(tagMemProf)
dumpint(uint64(uintptr(unsafe.Pointer())))
dumpint(uint64())
dumpint(uint64())
for := uintptr(0); < ; ++ {
:= []
:= findfunc()
if !.valid() {
var [64]byte
:= len()
--
[] = ')'
if == 0 {
--
[] = '0'
} else {
for > 0 {
--
[] = "0123456789abcdef"[&15]
>>= 4
}
}
--
[] = 'x'
--
[] = '0'
--
[] = '('
dumpslice([:])
dumpstr("?")
dumpint(0)
} else {
dumpstr(funcname())
if > 0 && > .entry {
--
}
, := funcline(, )
dumpstr()
dumpint(uint64())
}
}
dumpint(uint64())
dumpint(uint64())
}
func () {
assertWorldStopped()
iterate_memprof(dumpmemprof_callback)
for , := range mheap_.allspans {
if .state.get() != mSpanInUse {
continue
}
for := .specials; != nil; = .next {
if .kind != _KindSpecialProfile {
continue
}
:= (*specialprofile)(unsafe.Pointer())
:= .base() + uintptr(.special.offset)
dumpint(tagAllocSample)
dumpint(uint64())
dumpint(uint64(uintptr(unsafe.Pointer(.b))))
}
}
}
var dumphdr = []byte("go1.7 heap dump\n")
func ( *MemStats) {
assertWorldStopped()
for , := range mheap_.allspans {
if .state.get() == mSpanInUse {
.ensureSwept()
}
}
memclrNoHeapPointers(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
dwrite(unsafe.Pointer(&dumphdr[0]), uintptr(len(dumphdr)))
dumpparams()
dumpitabs()
dumpobjs()
dumpgs()
dumpms()
dumproots()
dumpmemstats()
dumpmemprof()
dumpint(tagEOF)
flush()
}
func ( uintptr, *MemStats) {
assertWorldStopped()
:= getg()
casgstatus(.m.curg, _Grunning, _Gwaiting)
.waitreason = waitReasonDumpingHeap
updatememstats()
dumpfd =
mdump()
dumpfd = 0
if tmpbuf != nil {
sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
tmpbuf = nil
}
casgstatus(.m.curg, _Gwaiting, _Grunning)
}
func ( bitvector) {
dumpbv(&, 0)
dumpint(fieldKindEol)
}
func ( uintptr, uintptr) bitvector {
:= / sys.PtrSize
if uintptr(len(tmpbuf)) < /8+1 {
if tmpbuf != nil {
sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
}
:= /8 + 1
:= sysAlloc(, &memstats.other_sys)
if == nil {
throw("heapdump: out of memory")
}
tmpbuf = (*[1 << 30]byte)()[:]
}
for := uintptr(0); < /8+1; ++ {
tmpbuf[] = 0
}
:= uintptr(0)
:= heapBitsForAddr()
for ; < ; ++ {
if !.morePointers() {
break
}
if .isPointer() {
tmpbuf[/8] |= 1 << ( % 8)
}
= .next()
}
return bitvector{int32(), &tmpbuf[0]}
}