mirror of
https://github.com/golang/go
synced 2024-11-05 14:56:10 -07:00
runtime: include scalar slots in GC scan work metric
The garbage collector predicts how much "scan work" must be done in a cycle to determine how much work should be done by mutators when they allocate. Most code doesn't care what units the scan work is in: it simply knows that a certain amount of scan work has to be done in the cycle. Currently, the GC uses the number of pointer slots scanned as the scan work on the theory that this is the bulk of the time spent in the garbage collector and hence reflects real CPU resource usage. However, this metric is difficult to estimate at the beginning of a cycle. Switch to counting the total number of bytes scanned, including both pointer and scalar slots. This is still less than the total marked heap since it omits no-scan objects and no-scan tails of objects. This metric may not reflect absolute performance as well as the count of scanned pointer slots (though it still takes time to scan scalar fields), but it will be much easier to estimate robustly, which is more important. Change-Id: Ie3a5eeeb0384a1ca566f61b2f11e9ff3a75ca121 Reviewed-on: https://go-review.googlesource.com/9694 Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
c4931a8433
commit
53c53984e7
@ -540,7 +540,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
|
|||||||
|
|
||||||
arena_start := mheap_.arena_start
|
arena_start := mheap_.arena_start
|
||||||
arena_used := mheap_.arena_used
|
arena_used := mheap_.arena_used
|
||||||
scanWork := int64(0)
|
|
||||||
|
|
||||||
for i := uintptr(0); i < n; {
|
for i := uintptr(0); i < n; {
|
||||||
// Find bits for the next word.
|
// Find bits for the next word.
|
||||||
@ -553,7 +552,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
|
|||||||
if bits&1 != 0 {
|
if bits&1 != 0 {
|
||||||
// Same work as in scanobject; see comments there.
|
// Same work as in scanobject; see comments there.
|
||||||
obj := *(*uintptr)(unsafe.Pointer(b + i))
|
obj := *(*uintptr)(unsafe.Pointer(b + i))
|
||||||
scanWork++
|
|
||||||
if obj != 0 && arena_start <= obj && obj < arena_used {
|
if obj != 0 && arena_start <= obj && obj < arena_used {
|
||||||
if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
|
if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
|
||||||
checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
|
checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
|
||||||
@ -568,7 +566,7 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gcw.scanWork += scanWork
|
gcw.scanWork += int64(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanobject scans the object starting at b, adding pointers to gcw.
|
// scanobject scans the object starting at b, adding pointers to gcw.
|
||||||
@ -579,7 +577,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
|
|||||||
func scanobject(b uintptr, gcw *gcWork) {
|
func scanobject(b uintptr, gcw *gcWork) {
|
||||||
arena_start := mheap_.arena_start
|
arena_start := mheap_.arena_start
|
||||||
arena_used := mheap_.arena_used
|
arena_used := mheap_.arena_used
|
||||||
scanWork := int64(0)
|
|
||||||
|
|
||||||
// Find bits of the beginning of the object.
|
// Find bits of the beginning of the object.
|
||||||
// b must point to the beginning of a heap object, so
|
// b must point to the beginning of a heap object, so
|
||||||
@ -591,7 +588,8 @@ func scanobject(b uintptr, gcw *gcWork) {
|
|||||||
throw("scanobject n == 0")
|
throw("scanobject n == 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uintptr(0); i < n; i += ptrSize {
|
var i uintptr
|
||||||
|
for i = 0; i < n; i += ptrSize {
|
||||||
// Find bits for this word.
|
// Find bits for this word.
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
// Avoid needless hbits.next() on last iteration.
|
// Avoid needless hbits.next() on last iteration.
|
||||||
@ -616,16 +614,6 @@ func scanobject(b uintptr, gcw *gcWork) {
|
|||||||
|
|
||||||
obj := *(*uintptr)(unsafe.Pointer(b + i))
|
obj := *(*uintptr)(unsafe.Pointer(b + i))
|
||||||
|
|
||||||
// Track the scan work performed as a way to estimate
|
|
||||||
// GC time. We use the number of pointers scanned
|
|
||||||
// because pointer scanning dominates the cost of
|
|
||||||
// scanning.
|
|
||||||
//
|
|
||||||
// TODO(austin): Consider counting only pointers into
|
|
||||||
// the heap, since nil and non-heap pointers are
|
|
||||||
// probably cheap to scan.
|
|
||||||
scanWork++
|
|
||||||
|
|
||||||
// At this point we have extracted the next potential pointer.
|
// At this point we have extracted the next potential pointer.
|
||||||
// Check if it points into heap.
|
// Check if it points into heap.
|
||||||
if obj != 0 && arena_start <= obj && obj < arena_used {
|
if obj != 0 && arena_start <= obj && obj < arena_used {
|
||||||
@ -640,7 +628,7 @@ func scanobject(b uintptr, gcw *gcWork) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
gcw.bytesMarked += uint64(n)
|
gcw.bytesMarked += uint64(n)
|
||||||
gcw.scanWork += scanWork
|
gcw.scanWork += int64(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shade the object if it isn't already.
|
// Shade the object if it isn't already.
|
||||||
|
Loading…
Reference in New Issue
Block a user