[ARM] Fix typo in comment in arm_expand_prologue
[official-gcc.git] / libgo / go / runtime / heapdump.go
blob0db53f544a5303b1971e8e1e68f400cf6722db7f
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Implementation of runtime/debug.WriteHeapDump. Writes all
6 // objects in the heap plus additional info (roots, threads,
7 // finalizers, etc.) to a file.
9 // The format of the dumped file is described at
10 // https://golang.org/s/go15heapdump.
12 package runtime
14 import (
15 "runtime/internal/sys"
16 "unsafe"
19 //go:linkname runtime_debug_WriteHeapDump runtime_debug.WriteHeapDump
20 func runtime_debug_WriteHeapDump(fd uintptr) {
21 stopTheWorld("write heap dump")
23 systemstack(func() {
24 writeheapdump_m(fd)
27 startTheWorld()
30 const (
31 fieldKindEol = 0
32 fieldKindPtr = 1
33 fieldKindIface = 2
34 fieldKindEface = 3
35 tagEOF = 0
36 tagObject = 1
37 tagOtherRoot = 2
38 tagType = 3
39 tagGoroutine = 4
40 tagStackFrame = 5
41 tagParams = 6
42 tagFinalizer = 7
43 tagItab = 8
44 tagOSThread = 9
45 tagMemStats = 10
46 tagQueuedFinalizer = 11
47 tagData = 12
48 tagBSS = 13
49 tagDefer = 14
50 tagPanic = 15
51 tagMemProf = 16
52 tagAllocSample = 17
55 var dumpfd uintptr // fd to write the dump to.
56 var tmpbuf []byte
58 // buffer of pending write data
59 const (
60 bufSize = 4096
63 var buf [bufSize]byte
64 var nbuf uintptr
66 func dwrite(data unsafe.Pointer, len uintptr) {
67 if len == 0 {
68 return
70 if nbuf+len <= bufSize {
71 copy(buf[nbuf:], (*[bufSize]byte)(data)[:len])
72 nbuf += len
73 return
76 write(dumpfd, unsafe.Pointer(&buf), int32(nbuf))
77 if len >= bufSize {
78 write(dumpfd, data, int32(len))
79 nbuf = 0
80 } else {
81 copy(buf[:], (*[bufSize]byte)(data)[:len])
82 nbuf = len
86 func dwritebyte(b byte) {
87 dwrite(unsafe.Pointer(&b), 1)
90 func flush() {
91 write(dumpfd, unsafe.Pointer(&buf), int32(nbuf))
92 nbuf = 0
95 // Cache of types that have been serialized already.
96 // We use a type's hash field to pick a bucket.
97 // Inside a bucket, we keep a list of types that
98 // have been serialized so far, most recently used first.
99 // Note: when a bucket overflows we may end up
100 // serializing a type more than once. That's ok.
101 const (
102 typeCacheBuckets = 256
103 typeCacheAssoc = 4
106 type typeCacheBucket struct {
107 t [typeCacheAssoc]*_type
110 var typecache [typeCacheBuckets]typeCacheBucket
112 // dump a uint64 in a varint format parseable by encoding/binary
113 func dumpint(v uint64) {
114 var buf [10]byte
115 var n int
116 for v >= 0x80 {
117 buf[n] = byte(v | 0x80)
119 v >>= 7
121 buf[n] = byte(v)
123 dwrite(unsafe.Pointer(&buf), uintptr(n))
126 func dumpbool(b bool) {
127 if b {
128 dumpint(1)
129 } else {
130 dumpint(0)
134 // dump varint uint64 length followed by memory contents
135 func dumpmemrange(data unsafe.Pointer, len uintptr) {
136 dumpint(uint64(len))
137 dwrite(data, len)
140 func dumpslice(b []byte) {
141 dumpint(uint64(len(b)))
142 if len(b) > 0 {
143 dwrite(unsafe.Pointer(&b[0]), uintptr(len(b)))
147 func dumpstr(s string) {
148 sp := stringStructOf(&s)
149 dumpmemrange(sp.str, uintptr(sp.len))
152 // dump information for a type
153 func dumptype(t *_type) {
154 if t == nil {
155 return
158 // If we've definitely serialized the type before,
159 // no need to do it again.
160 b := &typecache[t.hash&(typeCacheBuckets-1)]
161 if t == b.t[0] {
162 return
164 for i := 1; i < typeCacheAssoc; i++ {
165 if t == b.t[i] {
166 // Move-to-front
167 for j := i; j > 0; j-- {
168 b.t[j] = b.t[j-1]
170 b.t[0] = t
171 return
175 // Might not have been dumped yet. Dump it and
176 // remember we did so.
177 for j := typeCacheAssoc - 1; j > 0; j-- {
178 b.t[j] = b.t[j-1]
180 b.t[0] = t
182 // dump the type
183 dumpint(tagType)
184 dumpint(uint64(uintptr(unsafe.Pointer(t))))
185 dumpint(uint64(t.size))
186 if x := t.uncommontype; x == nil || t.pkgPath == nil || *t.pkgPath == "" {
187 dumpstr(*t.string)
188 } else {
189 pkgpathstr := *t.pkgPath
190 pkgpath := stringStructOf(&pkgpathstr)
191 namestr := *t.name
192 name := stringStructOf(&namestr)
193 dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
194 dwrite(pkgpath.str, uintptr(pkgpath.len))
195 dwritebyte('.')
196 dwrite(name.str, uintptr(name.len))
198 dumpbool(t.kind&kindDirectIface == 0 || t.kind&kindNoPointers == 0)
201 // dump an object
202 func dumpobj(obj unsafe.Pointer, size uintptr, bv bitvector) {
203 dumpbvtypes(&bv, obj)
204 dumpint(tagObject)
205 dumpint(uint64(uintptr(obj)))
206 dumpmemrange(obj, size)
207 dumpfields(bv)
210 func dumpotherroot(description string, to unsafe.Pointer) {
211 dumpint(tagOtherRoot)
212 dumpstr(description)
213 dumpint(uint64(uintptr(to)))
216 func dumpfinalizer(obj unsafe.Pointer, fn *funcval, ft *functype, ot *ptrtype) {
217 dumpint(tagFinalizer)
218 dumpint(uint64(uintptr(obj)))
219 dumpint(uint64(uintptr(unsafe.Pointer(fn))))
220 dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
221 dumpint(uint64(uintptr(unsafe.Pointer(ft))))
222 dumpint(uint64(uintptr(unsafe.Pointer(ot))))
225 type childInfo struct {
226 // Information passed up from the callee frame about
227 // the layout of the outargs region.
228 argoff uintptr // where the arguments start in the frame
229 arglen uintptr // size of args region
230 args bitvector // if args.n >= 0, pointer map of args region
231 sp *uint8 // callee sp
232 depth uintptr // depth in call stack (0 == most recent)
235 // dump kinds & offsets of interesting fields in bv
236 func dumpbv(cbv *bitvector, offset uintptr) {
237 bv := gobv(*cbv)
238 for i := uintptr(0); i < bv.n; i++ {
239 if bv.bytedata[i/8]>>(i%8)&1 == 1 {
240 dumpint(fieldKindPtr)
241 dumpint(uint64(offset + i*sys.PtrSize))
246 func dumpgoroutine(gp *g) {
247 sp := gp.syscallsp
249 dumpint(tagGoroutine)
250 dumpint(uint64(uintptr(unsafe.Pointer(gp))))
251 dumpint(uint64(sp))
252 dumpint(uint64(gp.goid))
253 dumpint(uint64(gp.gopc))
254 dumpint(uint64(readgstatus(gp)))
255 dumpbool(isSystemGoroutine(gp))
256 dumpbool(false) // isbackground
257 dumpint(uint64(gp.waitsince))
258 dumpstr(gp.waitreason)
259 dumpint(0)
260 dumpint(uint64(uintptr(unsafe.Pointer(gp.m))))
261 dumpint(uint64(uintptr(unsafe.Pointer(gp._defer))))
262 dumpint(uint64(uintptr(unsafe.Pointer(gp._panic))))
264 // dump defer & panic records
265 for d := gp._defer; d != nil; d = d.link {
266 dumpint(tagDefer)
267 dumpint(uint64(uintptr(unsafe.Pointer(d))))
268 dumpint(uint64(uintptr(unsafe.Pointer(gp))))
269 dumpint(0)
270 dumpint(0)
271 dumpint(uint64(uintptr(unsafe.Pointer(d.pfn))))
272 dumpint(0)
273 dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
275 for p := gp._panic; p != nil; p = p.link {
276 dumpint(tagPanic)
277 dumpint(uint64(uintptr(unsafe.Pointer(p))))
278 dumpint(uint64(uintptr(unsafe.Pointer(gp))))
279 eface := efaceOf(&p.arg)
280 dumpint(uint64(uintptr(unsafe.Pointer(eface._type))))
281 dumpint(uint64(uintptr(unsafe.Pointer(eface.data))))
282 dumpint(0) // was p->defer, no longer recorded
283 dumpint(uint64(uintptr(unsafe.Pointer(p.link))))
287 func dumpgs() {
288 // goroutines & stacks
289 for i := 0; uintptr(i) < allglen; i++ {
290 gp := allgs[i]
291 status := readgstatus(gp) // The world is stopped so gp will not be in a scan state.
292 switch status {
293 default:
294 print("runtime: unexpected G.status ", hex(status), "\n")
295 throw("dumpgs in STW - bad status")
296 case _Gdead:
297 // ok
298 case _Grunnable,
299 _Gsyscall,
300 _Gwaiting:
301 dumpgoroutine(gp)
306 func finq_callback(fn *funcval, obj unsafe.Pointer, ft *functype, ot *ptrtype) {
307 dumpint(tagQueuedFinalizer)
308 dumpint(uint64(uintptr(obj)))
309 dumpint(uint64(uintptr(unsafe.Pointer(fn))))
310 dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
311 dumpint(uint64(uintptr(unsafe.Pointer(ft))))
312 dumpint(uint64(uintptr(unsafe.Pointer(ot))))
315 func dumproots() {
316 // MSpan.types
317 for _, s := range mheap_.allspans {
318 if s.state == _MSpanInUse {
319 // Finalizers
320 for sp := s.specials; sp != nil; sp = sp.next {
321 if sp.kind != _KindSpecialFinalizer {
322 continue
324 spf := (*specialfinalizer)(unsafe.Pointer(sp))
325 p := unsafe.Pointer(s.base() + uintptr(spf.special.offset))
326 dumpfinalizer(p, spf.fn, spf.ft, spf.ot)
331 // Finalizer queue
332 iterate_finq(finq_callback)
335 // Bit vector of free marks.
336 // Needs to be as big as the largest number of objects per span.
337 var freemark [_PageSize / 8]bool
339 func dumpobjs() {
340 for _, s := range mheap_.allspans {
341 if s.state != _MSpanInUse {
342 continue
344 p := s.base()
345 size := s.elemsize
346 n := (s.npages << _PageShift) / size
347 if n > uintptr(len(freemark)) {
348 throw("freemark array doesn't have enough entries")
351 for freeIndex := uintptr(0); freeIndex < s.nelems; freeIndex++ {
352 if s.isFree(freeIndex) {
353 freemark[freeIndex] = true
357 for j := uintptr(0); j < n; j, p = j+1, p+size {
358 if freemark[j] {
359 freemark[j] = false
360 continue
362 dumpobj(unsafe.Pointer(p), size, makeheapobjbv(p, size))
367 func dumpparams() {
368 dumpint(tagParams)
369 x := uintptr(1)
370 if *(*byte)(unsafe.Pointer(&x)) == 1 {
371 dumpbool(false) // little-endian ptrs
372 } else {
373 dumpbool(true) // big-endian ptrs
375 dumpint(sys.PtrSize)
376 dumpint(uint64(mheap_.arena_start))
377 dumpint(uint64(mheap_.arena_used))
378 dumpstr(sys.GOARCH)
379 dumpstr(sys.Goexperiment)
380 dumpint(uint64(ncpu))
383 func dumpms() {
384 for mp := allm; mp != nil; mp = mp.alllink {
385 dumpint(tagOSThread)
386 dumpint(uint64(uintptr(unsafe.Pointer(mp))))
387 dumpint(uint64(mp.id))
388 dumpint(mp.procid)
392 func dumpmemstats() {
393 dumpint(tagMemStats)
394 dumpint(memstats.alloc)
395 dumpint(memstats.total_alloc)
396 dumpint(memstats.sys)
397 dumpint(memstats.nlookup)
398 dumpint(memstats.nmalloc)
399 dumpint(memstats.nfree)
400 dumpint(memstats.heap_alloc)
401 dumpint(memstats.heap_sys)
402 dumpint(memstats.heap_idle)
403 dumpint(memstats.heap_inuse)
404 dumpint(memstats.heap_released)
405 dumpint(memstats.heap_objects)
406 dumpint(memstats.stacks_inuse)
407 dumpint(memstats.stacks_sys)
408 dumpint(memstats.mspan_inuse)
409 dumpint(memstats.mspan_sys)
410 dumpint(memstats.mcache_inuse)
411 dumpint(memstats.mcache_sys)
412 dumpint(memstats.buckhash_sys)
413 dumpint(memstats.gc_sys)
414 dumpint(memstats.other_sys)
415 dumpint(memstats.next_gc)
416 dumpint(memstats.last_gc)
417 dumpint(memstats.pause_total_ns)
418 for i := 0; i < 256; i++ {
419 dumpint(memstats.pause_ns[i])
421 dumpint(uint64(memstats.numgc))
424 func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *location, size, allocs, frees uintptr) {
425 stk := (*[100000]location)(unsafe.Pointer(pstk))
426 dumpint(tagMemProf)
427 dumpint(uint64(uintptr(unsafe.Pointer(b))))
428 dumpint(uint64(size))
429 dumpint(uint64(nstk))
430 for i := uintptr(0); i < nstk; i++ {
431 pc := stk[i].pc
432 fn := stk[i].function
433 file := stk[i].filename
434 line := stk[i].lineno
435 if fn == "" {
436 var buf [64]byte
437 n := len(buf)
439 buf[n] = ')'
440 if pc == 0 {
442 buf[n] = '0'
443 } else {
444 for pc > 0 {
446 buf[n] = "0123456789abcdef"[pc&15]
447 pc >>= 4
451 buf[n] = 'x'
453 buf[n] = '0'
455 buf[n] = '('
456 dumpslice(buf[n:])
457 dumpstr("?")
458 dumpint(0)
459 } else {
460 dumpstr(fn)
461 dumpstr(file)
462 dumpint(uint64(line))
465 dumpint(uint64(allocs))
466 dumpint(uint64(frees))
469 func dumpmemprof() {
470 iterate_memprof(dumpmemprof_callback)
471 for _, s := range mheap_.allspans {
472 if s.state != _MSpanInUse {
473 continue
475 for sp := s.specials; sp != nil; sp = sp.next {
476 if sp.kind != _KindSpecialProfile {
477 continue
479 spp := (*specialprofile)(unsafe.Pointer(sp))
480 p := s.base() + uintptr(spp.special.offset)
481 dumpint(tagAllocSample)
482 dumpint(uint64(p))
483 dumpint(uint64(uintptr(unsafe.Pointer(spp.b))))
488 var dumphdr = []byte("go1.7 heap dump\n")
490 func mdump() {
491 // make sure we're done sweeping
492 for _, s := range mheap_.allspans {
493 if s.state == _MSpanInUse {
494 s.ensureSwept()
497 memclrNoHeapPointers(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
498 dwrite(unsafe.Pointer(&dumphdr[0]), uintptr(len(dumphdr)))
499 dumpparams()
500 dumpobjs()
501 dumpgs()
502 dumpms()
503 dumproots()
504 dumpmemstats()
505 dumpmemprof()
506 dumpint(tagEOF)
507 flush()
510 func writeheapdump_m(fd uintptr) {
511 _g_ := getg()
512 casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
513 _g_.waitreason = "dumping heap"
515 // Update stats so we can dump them.
516 // As a side effect, flushes all the MCaches so the MSpan.freelist
517 // lists contain all the free objects.
518 updatememstats(nil)
520 // Set dump file.
521 dumpfd = fd
523 // Call dump routine.
524 mdump()
526 // Reset dump file.
527 dumpfd = 0
528 if tmpbuf != nil {
529 sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
530 tmpbuf = nil
533 casgstatus(_g_.m.curg, _Gwaiting, _Grunning)
536 // dumpint() the kind & offset of each field in an object.
537 func dumpfields(bv bitvector) {
538 dumpbv(&bv, 0)
539 dumpint(fieldKindEol)
542 // The heap dump reader needs to be able to disambiguate
543 // Eface entries. So it needs to know every type that might
544 // appear in such an entry. The following routine accomplishes that.
545 // TODO(rsc, khr): Delete - no longer possible.
547 // Dump all the types that appear in the type field of
548 // any Eface described by this bit vector.
549 func dumpbvtypes(bv *bitvector, base unsafe.Pointer) {
552 func makeheapobjbv(p uintptr, size uintptr) bitvector {
553 // Extend the temp buffer if necessary.
554 nptr := size / sys.PtrSize
555 if uintptr(len(tmpbuf)) < nptr/8+1 {
556 if tmpbuf != nil {
557 sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
559 n := nptr/8 + 1
560 p := sysAlloc(n, &memstats.other_sys)
561 if p == nil {
562 throw("heapdump: out of memory")
564 tmpbuf = (*[1 << 30]byte)(p)[:n]
566 // Convert heap bitmap to pointer bitmap.
567 for i := uintptr(0); i < nptr/8+1; i++ {
568 tmpbuf[i] = 0
570 i := uintptr(0)
571 hbits := heapBitsForAddr(p)
572 for ; i < nptr; i++ {
573 if i != 1 && !hbits.morePointers() {
574 break // end of object
576 if hbits.isPointer() {
577 tmpbuf[i/8] |= 1 << (i % 8)
579 hbits = hbits.next()
581 return bitvector{int32(i), &tmpbuf[0]}
584 type gobitvector struct {
585 n uintptr
586 bytedata []uint8
589 func gobv(bv bitvector) gobitvector {
590 return gobitvector{
591 uintptr(bv.n),
592 (*[1 << 30]byte)(unsafe.Pointer(bv.bytedata))[:(bv.n+7)/8],