diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index dcb232a995..60fc8e590b 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -270,11 +270,11 @@ 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 +// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next +// timer is less than 60 ms from now. Since osRelaxing may reduce +// timer resolution to 15.6 ms, this keeps timer error under roughly 1 +// part in 4. +const osRelaxMinNS = 60 * 1e6 // osRelax is called by the scheduler when transitioning to and from // all Ps being idle. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 0219d2d77d..4f61f6164b 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3808,22 +3808,23 @@ func sysmon() { if scavengelimit < forcegcperiod { maxsleep = scavengelimit / 2 } - 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 + shouldRelax := true + if osRelaxMinNS > 0 { + lock(&timers.lock) + if timers.sleeping { + now := nanotime() + next := timers.sleepUntil + if next-now < osRelaxMinNS { + shouldRelax = false + } } + unlock(&timers.lock) } - if maxsleep > 0 { + if shouldRelax { osRelax(true) - notetsleep(&sched.sysmonnote, maxsleep) + } + notetsleep(&sched.sysmonnote, maxsleep) + if shouldRelax { osRelax(false) } lock(&sched.lock) diff --git a/src/runtime/relax_stub.go b/src/runtime/relax_stub.go index 648788118e..81ed1291b8 100644 --- a/src/runtime/relax_stub.go +++ b/src/runtime/relax_stub.go @@ -6,11 +6,11 @@ package runtime -// osRelaxDelay is the number of nanoseconds of idleness to tolerate -// before performing an osRelax. Since osRelax may reduce the +// osRelaxMinNS is the number of nanoseconds of idleness to tolerate +// without 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 +const osRelaxMinNS = 0 // osRelax is called by the scheduler when transitioning to and from // all Ps being idle. diff --git a/src/runtime/time.go b/src/runtime/time.go index 88ab8b9c02..abf200d7d3 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -31,6 +31,7 @@ var timers struct { created bool sleeping bool rescheduling bool + sleepUntil int64 waitnote note t []*timer } @@ -209,6 +210,7 @@ func timerproc() { } // At least one timer pending. Sleep until then. timers.sleeping = true + timers.sleepUntil = now + delta noteclear(&timers.waitnote) unlock(&timers.lock) notetsleepg(&timers.waitnote, delta)