Skip to content

Commit 25895d1

Browse files
mknyszekgopherbot
authored andcommitted
runtime: make all GC mark workers yield for forEachP
Currently dedicated GC mark workers really try to avoid getting preempted. The one exception is for a pending STW, indicated by sched.gcwaiting. This is currently fine because other kinds of preemptions don't matter to the mark workers: they're intentionally bound to their P. With the new execution tracer we're going to want to use forEachP to get the attention of all Ps. We may want to do this during a GC cycle. forEachP doesn't set sched.gcwaiting, so it may end up waiting the full GC mark phase, burning a thread and a P in the meantime. This can mean basically seconds of waiting and trying to preempt GC mark workers. This change makes all mark workers yield if (*p).runSafePointFn != 0 so that the workers actually yield somewhat promptly in response to a forEachP attempt. Change-Id: I7430baf326886b9f7a868704482a224dae7c9bba Reviewed-on: https://go-review.googlesource.com/c/go/+/537235 Reviewed-by: Michael Pratt <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Mauri de Souza Meneguzzo <[email protected]> Auto-Submit: Michael Knyszek <[email protected]>
1 parent ff7cf2d commit 25895d1

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

src/runtime/mgcmark.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -1068,7 +1068,7 @@ func gcDrainMarkWorkerFractional(gcw *gcWork) {
10681068
// credit to gcController.bgScanCredit every gcCreditSlack units of
10691069
// scan work.
10701070
//
1071-
// gcDrain will always return if there is a pending STW.
1071+
// gcDrain will always return if there is a pending STW or forEachP.
10721072
//
10731073
// Disabling write barriers is necessary to ensure that after we've
10741074
// confirmed that we've drained gcw, that we don't accidentally end
@@ -1084,7 +1084,10 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
10841084
throw("gcDrain phase incorrect")
10851085
}
10861086

1087+
// N.B. We must be running in a non-preemptible context, so it's
1088+
// safe to hold a reference to our P here.
10871089
gp := getg().m.curg
1090+
pp := gp.m.p.ptr()
10881091
preemptible := flags&gcDrainUntilPreempt != 0
10891092
flushBgCredit := flags&gcDrainFlushBgCredit != 0
10901093
idle := flags&gcDrainIdle != 0
@@ -1106,8 +1109,9 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
11061109

11071110
// Drain root marking jobs.
11081111
if work.markrootNext < work.markrootJobs {
1109-
// Stop if we're preemptible or if someone wants to STW.
1110-
for !(gp.preempt && (preemptible || sched.gcwaiting.Load())) {
1112+
// Stop if we're preemptible, if someone wants to STW, or if
1113+
// someone is calling forEachP.
1114+
for !(gp.preempt && (preemptible || sched.gcwaiting.Load() || pp.runSafePointFn != 0)) {
11111115
job := atomic.Xadd(&work.markrootNext, +1) - 1
11121116
if job >= work.markrootJobs {
11131117
break
@@ -1120,8 +1124,16 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
11201124
}
11211125

11221126
// Drain heap marking jobs.
1123-
// Stop if we're preemptible or if someone wants to STW.
1124-
for !(gp.preempt && (preemptible || sched.gcwaiting.Load())) {
1127+
//
1128+
// Stop if we're preemptible, if someone wants to STW, or if
1129+
// someone is calling forEachP.
1130+
//
1131+
// TODO(mknyszek): Consider always checking gp.preempt instead
1132+
// of having the preempt flag, and making an exception for certain
1133+
// mark workers in retake. That might be simpler than trying to
1134+
// enumerate all the reasons why we might want to preempt, even
1135+
// if we're supposed to be mostly non-preemptible.
1136+
for !(gp.preempt && (preemptible || sched.gcwaiting.Load() || pp.runSafePointFn != 0)) {
11251137
// Try to keep work available on the global queue. We used to
11261138
// check if there were waiting workers, but it's better to
11271139
// just keep work available than to make workers wait. In the

0 commit comments

Comments
 (0)