Skip to content

Commit 500c88d

Browse files
committed
runtime: yield to GC coordinator after assist completion
Currently it's possible for the GC assist to signal completion of the mark phase, which puts the GC coordinator goroutine on the current P's run queue, and then return to mutator code that delays until the next forced preemption before actually yielding control to the GC coordinator, dragging out completion of the mark phase. This delay can be further exacerbated if the mutator makes other goroutines runnable before yielding control, since this will push the GC coordinator on the back of the P's run queue. To fix this, this adds a Gosched to the assist if it completed the mark phase. This immediately and directly yields control to the GC coordinator. This already happens implicitly in the background mark workers because they park immediately after completing the mark. This is one of the reasons completion of the mark phase is being dragged out and allowing the mutator to allocate without assisting, leading to the large heap goal overshoot in issue #11677. This is also a prerequisite to making the assist block when it can't pay off its debt. Change-Id: I586adfbecb3ca042a37966752c1dc757f5c7fc78 Reviewed-on: https://go-review.googlesource.com/12670 Reviewed-by: Russ Cox <[email protected]>
1 parent 4f188c2 commit 500c88d

File tree

2 files changed

+12
-0
lines changed

2 files changed

+12
-0
lines changed

src/runtime/mgc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,10 @@ func (s *bgMarkSignal) wait() {
706706
// complete signals the completion of this phase of marking. This can
707707
// be called multiple times during a cycle; only the first call has
708708
// any effect.
709+
//
710+
// The caller should arrange to deschedule itself as soon as possible
711+
// after calling complete in order to let the coordinator goroutine
712+
// run.
709713
func (s *bgMarkSignal) complete() {
710714
if cas(&s.done, 0, 1) {
711715
// This is the first worker to reach this completion point.

src/runtime/mgcmark.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ func gcAssistAlloc(size uintptr, allowAssist bool) {
202202
}
203203

204204
// Perform assist work
205+
completed := false
205206
systemstack(func() {
206207
if atomicload(&gcBlackenEnabled) == 0 {
207208
// The gcBlackenEnabled check in malloc races with the
@@ -255,6 +256,7 @@ func gcAssistAlloc(size uintptr, allowAssist bool) {
255256
} else {
256257
work.bgMark1.complete()
257258
}
259+
completed = true
258260
}
259261
duration := nanotime() - startTime
260262
_p_ := gp.m.p.ptr()
@@ -264,6 +266,12 @@ func gcAssistAlloc(size uintptr, allowAssist bool) {
264266
_p_.gcAssistTime = 0
265267
}
266268
})
269+
270+
if completed {
271+
// We called complete() above, so we should yield to
272+
// the now-runnable GC coordinator.
273+
Gosched()
274+
}
267275
}
268276

269277
//go:nowritebarrier

0 commit comments

Comments
 (0)