Commit 7a8f39fa authored by Austin Clements's avatar Austin Clements

runtime: delay before osRelaxing

Currently, sysmon relaxes the Windows timer resolution as soon as the
Go process becomes idle. However, if it's going idle because of a
short sleep (< 15.6 ms), this can turn that short sleep into a long
sleep (15.6 ms).

To address this, wait for 60 ms of idleness before relaxing the timer
resolution. It would be better to check the time until the next wakeup
and relax immediately if it makes sense, but there's currently no
interaction between sysmon and the timer subsystem, so adding this
simple delay is a much simpler and safer change for late in the
release cycle.

Fixes #20937.

Change-Id: I817db24c3bdfa06dba04b7bc197cfd554363c379
Reviewed-on: https://go-review.googlesource.com/47832
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 5d16f975
......@@ -270,6 +270,12 @@ var useLoadLibraryEx bool
var timeBeginPeriodRetValue uint32
// osRelaxDelay indicates that sysmon should wait for 60 ms of
// idleness before osRelaxing. Since osRelaxing may reduce timer
// resolution to 15.6 ms, this keeps timer error under roughly 1 part
// in 4.
const osRelaxDelay = 60 * 1e6
// osRelax is called by the scheduler when transitioning to and from
// all Ps being idle.
//
......
......@@ -3808,9 +3808,24 @@ func sysmon() {
if scavengelimit < forcegcperiod {
maxsleep = scavengelimit / 2
}
osRelax(true)
notetsleep(&sched.sysmonnote, maxsleep)
osRelax(false)
if osRelaxDelay > 0 {
// Wait before osRelaxing in
// case something happens soon.
sleep1 := int64(osRelaxDelay)
if sleep1 > maxsleep {
sleep1 = maxsleep
}
if notetsleep(&sched.sysmonnote, sleep1) {
maxsleep = 0
} else {
maxsleep -= sleep1
}
}
if maxsleep > 0 {
osRelax(true)
notetsleep(&sched.sysmonnote, maxsleep)
osRelax(false)
}
lock(&sched.lock)
atomic.Store(&sched.sysmonwait, 0)
noteclear(&sched.sysmonnote)
......
......@@ -6,6 +6,12 @@
package runtime
// osRelaxDelay is the number of nanoseconds of idleness to tolerate
// before performing an osRelax. Since osRelax may reduce the
// precision of timers, this should be enough larger than the relaxed
// timer precision to keep the timer error acceptable.
const osRelaxDelay = 0
// osRelax is called by the scheduler when transitioning to and from
// all Ps being idle.
func osRelax(relax bool) {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment