Skip to content

Commit 53c5398

Browse files
committed
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 <[email protected]>
1 parent c4931a8 commit 53c5398

File tree

1 file changed

+4
-16
lines changed

1 file changed

+4
-16
lines changed

src/runtime/mgcmark.go

+4-16
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
540540

541541
arena_start := mheap_.arena_start
542542
arena_used := mheap_.arena_used
543-
scanWork := int64(0)
544543

545544
for i := uintptr(0); i < n; {
546545
// Find bits for the next word.
@@ -553,7 +552,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
553552
if bits&1 != 0 {
554553
// Same work as in scanobject; see comments there.
555554
obj := *(*uintptr)(unsafe.Pointer(b + i))
556-
scanWork++
557555
if obj != 0 && arena_start <= obj && obj < arena_used {
558556
if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
559557
checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
@@ -568,7 +566,7 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
568566
}
569567
}
570568

571-
gcw.scanWork += scanWork
569+
gcw.scanWork += int64(n)
572570
}
573571

574572
// scanobject scans the object starting at b, adding pointers to gcw.
@@ -579,7 +577,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
579577
func scanobject(b uintptr, gcw *gcWork) {
580578
arena_start := mheap_.arena_start
581579
arena_used := mheap_.arena_used
582-
scanWork := int64(0)
583580

584581
// Find bits of the beginning of the object.
585582
// b must point to the beginning of a heap object, so
@@ -591,7 +588,8 @@ func scanobject(b uintptr, gcw *gcWork) {
591588
throw("scanobject n == 0")
592589
}
593590

594-
for i := uintptr(0); i < n; i += ptrSize {
591+
var i uintptr
592+
for i = 0; i < n; i += ptrSize {
595593
// Find bits for this word.
596594
if i != 0 {
597595
// Avoid needless hbits.next() on last iteration.
@@ -616,16 +614,6 @@ func scanobject(b uintptr, gcw *gcWork) {
616614

617615
obj := *(*uintptr)(unsafe.Pointer(b + i))
618616

619-
// Track the scan work performed as a way to estimate
620-
// GC time. We use the number of pointers scanned
621-
// because pointer scanning dominates the cost of
622-
// scanning.
623-
//
624-
// TODO(austin): Consider counting only pointers into
625-
// the heap, since nil and non-heap pointers are
626-
// probably cheap to scan.
627-
scanWork++
628-
629617
// At this point we have extracted the next potential pointer.
630618
// Check if it points into heap.
631619
if obj != 0 && arena_start <= obj && obj < arena_used {
@@ -640,7 +628,7 @@ func scanobject(b uintptr, gcw *gcWork) {
640628
}
641629
}
642630
gcw.bytesMarked += uint64(n)
643-
gcw.scanWork += scanWork
631+
gcw.scanWork += int64(i)
644632
}
645633

646634
// Shade the object if it isn't already.

0 commit comments

Comments
 (0)