]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: run background mark helpers only if work is available
authorRick Hudson <rlh@golang.org>
Mon, 18 May 2015 20:02:37 +0000 (16:02 -0400)
committerRick Hudson <rlh@golang.org>
Tue, 19 May 2015 15:57:50 +0000 (15:57 +0000)
Prior to this CL whenever the GC marking was enabled and
a P was looking for work we supplied a G to help
the GC do its marking tasks. Once this G finished all
the marking available it would release the P to find another
available G. In the case where there was no work the P would drop
into findrunnable which would execute the mark helper G which would
immediately return and the P would drop into findrunnable again repeating
the process. Since the P was always given a G to run it never blocks.
This CL first checks if the GC mark helper G has available work and if
not the P immediately falls through to its blocking logic.

Fixes #10901

Change-Id: I94ac9646866ba64b7892af358888bc9950de23b5
Reviewed-on: https://go-review.googlesource.com/10189
Reviewed-by: Austin Clements <austin@google.com>
src/runtime/mgc.go
src/runtime/mgcwork.go
src/runtime/proc1.go

index fb2b21002030ca54943aebcdd91753cf26761700..ebecc4ffa820649e21df462a08417c1ae09541bf 100644 (file)
@@ -1168,6 +1168,18 @@ func gcBgMarkDone() {
        }
 }
 
+// gcMarkWorkAvailable determines if mark work is readily available.
+// It is used by the scheduler to decide if this p run a mark work.
+func gcMarkWorkAvailable(p *p) bool {
+       if !p.gcw.empty() {
+               return true
+       }
+       if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 {
+               return true // global work available
+       }
+       return false
+}
+
 // gcFlushGCWork disposes the gcWork caches of all Ps. The world must
 // be stopped.
 //go:nowritebarrier
index 9c32ae888042065499e4f5d8f22a36c72b7ddad1..930c644c0ad5f5964309009872557a694a1f230a 100644 (file)
@@ -182,6 +182,13 @@ func (w *gcWork) balance() {
        }
 }
 
+// empty returns true if w has no mark work available.
+//go:nowritebarrier
+func (w *gcWork) empty() bool {
+       wbuf := w.wbuf
+       return wbuf == 0 || wbuf.ptr().nobj == 0
+}
+
 // Internally, the GC work pool is kept in arrays in work buffers.
 // The gcWork interface caches a work buffer until full (or empty) to
 // avoid contending on the global work buffer lists.
index b0b3bf77116495a92861d384c8aab815c70e5108..54d6698b3feb4e89574208e5bec804640fb0ec11 100644 (file)
@@ -1479,7 +1479,7 @@ stop:
        // We have nothing to do. If we're in the GC mark phase and can
        // safely scan and blacken objects, run idle-time marking
        // rather than give up the P.
-       if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil {
+       if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil && gcMarkWorkAvailable(_p_) {
                _p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
                gp := _p_.gcBgMarkWorker
                casgstatus(gp, _Gwaiting, _Grunnable)