Skip to content

Commit

Permalink
runtime: track "scannable" bytes of heap
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
aclements committed May 6, 2015
1 parent 53c5398 commit 3be3cbd
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/runtime/malloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,16 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
dataSize = unsafe.Sizeof(_defer{})
}
heapBitsSetType(uintptr(x), size, dataSize, typ)
if dataSize > typ.size {
// Array allocation. If there are any
// pointers, GC has to scan to the last
// element.
if typ.ptrdata != 0 {
c.local_scan += dataSize - typ.size + typ.ptrdata
}
} else {
c.local_scan += typ.ptrdata
}
}

// GCmarkterminate allocates black
Expand Down
1 change: 1 addition & 0 deletions src/runtime/mcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type mcache struct {
// so they are grouped here for better caching.
next_sample int32 // trigger heap sample after allocating this many bytes
local_cachealloc uintptr // bytes allocated from cache since last lock of heap
local_scan uintptr // bytes of scannable heap allocated
// Allocator cache for tiny objects w/o pointers.
// See "Tiny allocator" comment in malloc.go.
tiny unsafe.Pointer
Expand Down
1 change: 1 addition & 0 deletions src/runtime/mgc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,7 @@ func gcMark(start_time int64) {
// Update other GC heap size stats.
memstats.heap_live = work.bytesMarked
memstats.heap_marked = work.bytesMarked
memstats.heap_scan = uint64(gcController.scanWork)

if trace.enabled {
traceHeapAlloc()
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/mgcmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,10 @@ func gcDrainN(gcw *gcWork, scanWork int64) {

// scanblock scans b as scanobject would, but using an explicit
// pointer bitmap instead of the heap bitmap.
//
// This is used to scan non-heap roots, so it does not update
// gcw.bytesMarked or gcw.scanWork.
//
//go:nowritebarrier
func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
// Use local copies of original parameters, so that a stack trace
Expand Down Expand Up @@ -565,8 +569,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
i += ptrSize
}
}

gcw.scanWork += int64(n)
}

// scanobject scans the object starting at b, adding pointers to gcw.
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/mheap.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ func mHeap_Alloc_m(h *mheap, npage uintptr, sizeclass int32, large bool) *mspan
// transfer stats from cache to global
memstats.heap_live += uint64(_g_.m.mcache.local_cachealloc)
_g_.m.mcache.local_cachealloc = 0
memstats.heap_scan += uint64(_g_.m.mcache.local_scan)
_g_.m.mcache.local_scan = 0
memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
_g_.m.mcache.local_tinyallocs = 0

Expand Down Expand Up @@ -656,6 +658,8 @@ func mHeap_Free(h *mheap, s *mspan, acct int32) {
lock(&h.lock)
memstats.heap_live += uint64(mp.mcache.local_cachealloc)
mp.mcache.local_cachealloc = 0
memstats.heap_scan += uint64(mp.mcache.local_scan)
mp.mcache.local_scan = 0
memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
mp.mcache.local_tinyallocs = 0
if acct != 0 {
Expand Down
7 changes: 7 additions & 0 deletions src/runtime/mstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ type mstats struct {
// excludes unmarked objects that have not yet been swept.
heap_live uint64

// heap_scan is the number of bytes of "scannable" heap. This
// is the live heap (as counted by heap_live), but omitting
// no-scan objects and no-scan tails of objects.
heap_scan uint64

// heap_marked is the number of bytes marked by the previous
// GC. After mark termination, heap_live == heap_marked, but
// unlike heap_live, heap_marked does not change until the
Expand Down Expand Up @@ -340,6 +345,8 @@ func purgecachedstats(c *mcache) {
if trace.enabled {
traceHeapAlloc()
}
memstats.heap_scan += uint64(c.local_scan)
c.local_scan = 0
memstats.tinyallocs += uint64(c.local_tinyallocs)
c.local_tinyallocs = 0
memstats.nlookup += uint64(c.local_nlookup)
Expand Down

0 comments on commit 3be3cbd

Please sign in to comment.