mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: usleep before stealing runnext only if not in syscall
In the scheduler's steal path, we usleep(3) before stealing a _Prunning P's runnext slot. Before CL 646198, we would not call usleep(3) if the P was in _Psyscall. After CL 646198, Ps with Gs in syscalls stay in _Prunning until stolen, meaning we might unnecessarily usleep(3) where we didn't before. This probably isn't a huge deal in most cases, but can cause some apparent slowdowns in microbenchmarks that frequently take the steal path while there are syscalling goroutines. Change-Id: I5bf3df10fe61cf8d7f0e9fe9522102de66faf344 Reviewed-on: https://go-review.googlesource.com/c/go/+/720441 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
410ef44f00
commit
d55ecea9e5
1 changed files with 30 additions and 17 deletions
|
|
@ -7507,6 +7507,8 @@ func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool)
|
||||||
// Try to steal from pp.runnext.
|
// Try to steal from pp.runnext.
|
||||||
if next := pp.runnext; next != 0 {
|
if next := pp.runnext; next != 0 {
|
||||||
if pp.status == _Prunning {
|
if pp.status == _Prunning {
|
||||||
|
if mp := pp.m.ptr(); mp != nil {
|
||||||
|
if gp := mp.curg; gp == nil || readgstatus(gp)&^_Gscan != _Gsyscall {
|
||||||
// Sleep to ensure that pp isn't about to run the g
|
// Sleep to ensure that pp isn't about to run the g
|
||||||
// we are about to steal.
|
// we are about to steal.
|
||||||
// The important use case here is when the g running
|
// The important use case here is when the g running
|
||||||
|
|
@ -7517,6 +7519,15 @@ func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool)
|
||||||
// between different Ps.
|
// between different Ps.
|
||||||
// A sync chan send/recv takes ~50ns as of time of
|
// A sync chan send/recv takes ~50ns as of time of
|
||||||
// writing, so 3us gives ~50x overshoot.
|
// writing, so 3us gives ~50x overshoot.
|
||||||
|
// If curg is nil, we assume that the P is likely
|
||||||
|
// to be in the scheduler. If curg isn't nil and isn't
|
||||||
|
// in a syscall, then it's either running, waiting, or
|
||||||
|
// runnable. In this case we want to sleep because the
|
||||||
|
// P might either call into the scheduler soon (running),
|
||||||
|
// or already is (since we found a waiting or runnable
|
||||||
|
// goroutine hanging off of a running P, suggesting it
|
||||||
|
// either recently transitioned out of running, or will
|
||||||
|
// transition to running shortly).
|
||||||
if !osHasLowResTimer {
|
if !osHasLowResTimer {
|
||||||
usleep(3)
|
usleep(3)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -7526,6 +7537,8 @@ func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool)
|
||||||
osyield()
|
osyield()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if !pp.runnext.cas(next, 0) {
|
if !pp.runnext.cas(next, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue