Skip to content

Commit e56c73f

Browse files
committed
runtime: look for idle p to run current goroutine when switching to GC or traceReader
This repairs one of the several causes of pauses uncovered by a GC microbenchmark. A pause can occur when a goroutine's quantum expires "at the same time" a GC is needed. The current M switches to running a GC worker, which means that the amount of available work has expanded by one. The GC worker, however, does not call ready, and does not itself conditionally wake a P (a "normal" thread would do this). This is also true if M switches to a traceReader. This is problem 4 in this list: #27732 (comment) Updates #27732. Change-Id: I6905365cac8504cde6faab2420f4421536551f0b Reviewed-on: https://go-review.googlesource.com/c/go/+/146817 Run-TryBot: David Chase <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Austin Clements <[email protected]>
1 parent 45be353 commit e56c73f

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

src/runtime/proc.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,15 +2487,22 @@ top:
24872487

24882488
var gp *g
24892489
var inheritTime bool
2490+
2491+
// Normal goroutines will check for need to wakeP in ready,
2492+
// but GCworkers and tracereaders will not, so the check must
2493+
// be done here instead.
2494+
tryWakeP := false
24902495
if trace.enabled || trace.shutdown {
24912496
gp = traceReader()
24922497
if gp != nil {
24932498
casgstatus(gp, _Gwaiting, _Grunnable)
24942499
traceGoUnpark(gp, 0)
2500+
tryWakeP = true
24952501
}
24962502
}
24972503
if gp == nil && gcBlackenEnabled != 0 {
24982504
gp = gcController.findRunnableGCWorker(_g_.m.p.ptr())
2505+
tryWakeP = tryWakeP || gp != nil
24992506
}
25002507
if gp == nil {
25012508
// Check the global runnable queue once in a while to ensure fairness.
@@ -2541,6 +2548,13 @@ top:
25412548
}
25422549
}
25432550

2551+
// If about to schedule a not-normal goroutine (a GCworker or tracereader),
2552+
// wake a P if there is one.
2553+
if tryWakeP {
2554+
if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
2555+
wakep()
2556+
}
2557+
}
25442558
if gp.lockedm != 0 {
25452559
// Hands off own p to the locked m,
25462560
// then blocks waiting for a new p.

0 commit comments

Comments
 (0)