Skip to content

Commit 3be3cbd

Browse files
committed
runtime: track "scannable" bytes of heap
This tracks the number of scannable bytes in the allocated heap. That is, bytes that the garbage collector must scan before reaching the last pointer field in each object. This will be used to compute a more robust estimate of the GC scan work. Change-Id: I1eecd45ef9cdd65b69d2afb5db5da885c80086bb Reviewed-on: https://go-review.googlesource.com/9695 Reviewed-by: Russ Cox <[email protected]>
1 parent 53c5398 commit 3be3cbd

File tree

6 files changed

+27
-2
lines changed

6 files changed

+27
-2
lines changed

src/runtime/malloc.go

+10
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,16 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
647647
dataSize = unsafe.Sizeof(_defer{})
648648
}
649649
heapBitsSetType(uintptr(x), size, dataSize, typ)
650+
if dataSize > typ.size {
651+
// Array allocation. If there are any
652+
// pointers, GC has to scan to the last
653+
// element.
654+
if typ.ptrdata != 0 {
655+
c.local_scan += dataSize - typ.size + typ.ptrdata
656+
}
657+
} else {
658+
c.local_scan += typ.ptrdata
659+
}
650660
}
651661

652662
// GCmarkterminate allocates black

src/runtime/mcache.go

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type mcache struct {
1313
// so they are grouped here for better caching.
1414
next_sample int32 // trigger heap sample after allocating this many bytes
1515
local_cachealloc uintptr // bytes allocated from cache since last lock of heap
16+
local_scan uintptr // bytes of scannable heap allocated
1617
// Allocator cache for tiny objects w/o pointers.
1718
// See "Tiny allocator" comment in malloc.go.
1819
tiny unsafe.Pointer

src/runtime/mgc.go

+1
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,7 @@ func gcMark(start_time int64) {
12791279
// Update other GC heap size stats.
12801280
memstats.heap_live = work.bytesMarked
12811281
memstats.heap_marked = work.bytesMarked
1282+
memstats.heap_scan = uint64(gcController.scanWork)
12821283

12831284
if trace.enabled {
12841285
traceHeapAlloc()

src/runtime/mgcmark.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ func gcDrainN(gcw *gcWork, scanWork int64) {
530530

531531
// scanblock scans b as scanobject would, but using an explicit
532532
// pointer bitmap instead of the heap bitmap.
533+
//
534+
// This is used to scan non-heap roots, so it does not update
535+
// gcw.bytesMarked or gcw.scanWork.
536+
//
533537
//go:nowritebarrier
534538
func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
535539
// Use local copies of original parameters, so that a stack trace
@@ -565,8 +569,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
565569
i += ptrSize
566570
}
567571
}
568-
569-
gcw.scanWork += int64(n)
570572
}
571573

572574
// scanobject scans the object starting at b, adding pointers to gcw.

src/runtime/mheap.go

+4
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ func mHeap_Alloc_m(h *mheap, npage uintptr, sizeclass int32, large bool) *mspan
398398
// transfer stats from cache to global
399399
memstats.heap_live += uint64(_g_.m.mcache.local_cachealloc)
400400
_g_.m.mcache.local_cachealloc = 0
401+
memstats.heap_scan += uint64(_g_.m.mcache.local_scan)
402+
_g_.m.mcache.local_scan = 0
401403
memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
402404
_g_.m.mcache.local_tinyallocs = 0
403405

@@ -656,6 +658,8 @@ func mHeap_Free(h *mheap, s *mspan, acct int32) {
656658
lock(&h.lock)
657659
memstats.heap_live += uint64(mp.mcache.local_cachealloc)
658660
mp.mcache.local_cachealloc = 0
661+
memstats.heap_scan += uint64(mp.mcache.local_scan)
662+
mp.mcache.local_scan = 0
659663
memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
660664
mp.mcache.local_tinyallocs = 0
661665
if acct != 0 {

src/runtime/mstats.go

+7
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ type mstats struct {
6969
// excludes unmarked objects that have not yet been swept.
7070
heap_live uint64
7171

72+
// heap_scan is the number of bytes of "scannable" heap. This
73+
// is the live heap (as counted by heap_live), but omitting
74+
// no-scan objects and no-scan tails of objects.
75+
heap_scan uint64
76+
7277
// heap_marked is the number of bytes marked by the previous
7378
// GC. After mark termination, heap_live == heap_marked, but
7479
// unlike heap_live, heap_marked does not change until the
@@ -340,6 +345,8 @@ func purgecachedstats(c *mcache) {
340345
if trace.enabled {
341346
traceHeapAlloc()
342347
}
348+
memstats.heap_scan += uint64(c.local_scan)
349+
c.local_scan = 0
343350
memstats.tinyallocs += uint64(c.local_tinyallocs)
344351
c.local_tinyallocs = 0
345352
memstats.nlookup += uint64(c.local_nlookup)

0 commit comments

Comments
 (0)