mirror of
https://github.com/golang/go
synced 2024-11-18 08:24:44 -07:00
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 <austin@google.com>
This commit is contained in:
parent
f4d51eb2f5
commit
913db7685e
@ -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
|
// gcFlushGCWork disposes the gcWork caches of all Ps. The world must
|
||||||
// be stopped.
|
// be stopped.
|
||||||
//go:nowritebarrier
|
//go:nowritebarrier
|
||||||
|
@ -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.
|
// Internally, the GC work pool is kept in arrays in work buffers.
|
||||||
// The gcWork interface caches a work buffer until full (or empty) to
|
// The gcWork interface caches a work buffer until full (or empty) to
|
||||||
// avoid contending on the global work buffer lists.
|
// avoid contending on the global work buffer lists.
|
||||||
|
@ -1479,7 +1479,7 @@ stop:
|
|||||||
// We have nothing to do. If we're in the GC mark phase and can
|
// We have nothing to do. If we're in the GC mark phase and can
|
||||||
// safely scan and blacken objects, run idle-time marking
|
// safely scan and blacken objects, run idle-time marking
|
||||||
// rather than give up the P.
|
// 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
|
_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
|
||||||
gp := _p_.gcBgMarkWorker
|
gp := _p_.gcBgMarkWorker
|
||||||
casgstatus(gp, _Gwaiting, _Grunnable)
|
casgstatus(gp, _Gwaiting, _Grunnable)
|
||||||
|
Loading…
Reference in New Issue
Block a user