mirror of
https://github.com/golang/go
synced 2024-11-26 15:36:59 -07:00
runtime: use next timer to decide whether to relax
Currently, sysmon waits 60 ms during idle before relaxing. This is primarily to avoid reducing the precision of short-duration timers. Of course, if there are no short-duration timers, this wastes 60 ms running the timer at high resolution. Improve this by instead inspecting the time until the next timer fires and relaxing the timer resolution immediately if the next timer won't fire for a while. Updates #20937. Change-Id: If4ad0a565b65a9b3e8c4cdc2eff1486968c79f24 Reviewed-on: https://go-review.googlesource.com/47833 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
7a8f39fa14
commit
093adeef40
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user