From: Rick Hudson Date: Mon, 18 May 2015 20:02:37 +0000 (-0400) Subject: runtime: run background mark helpers only if work is available X-Git-Tag: go1.5beta1~529 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=913db7685ec80bc9c56f357b09ced127fbf09a1e;p=gostls13.git runtime: run background mark helpers only if work is available 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 --- diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index fb2b210020..ebecc4ffa8 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -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 diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index 9c32ae8880..930c644c0a 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -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. diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index b0b3bf7711..54d6698b3f 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -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)