Skip to content

Commit 093adee

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 7a8f39f commit 093adee

File tree

4 files changed

+24
-21
lines changed

4 files changed

+24
-21
lines changed

src/runtime/os_windows.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,11 @@ var useLoadLibraryEx bool
270270

271271
var timeBeginPeriodRetValue uint32
272272

273-
// osRelaxDelay indicates that sysmon should wait for 60 ms of
274-
// idleness before osRelaxing. Since osRelaxing may reduce timer
275-
// resolution to 15.6 ms, this keeps timer error under roughly 1 part
276-
// in 4.
277-
const osRelaxDelay = 60 * 1e6
273+
// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
274+
// timer is less than 60 ms from now. Since osRelaxing may reduce
275+
// timer resolution to 15.6 ms, this keeps timer error under roughly 1
276+
// part in 4.
277+
const osRelaxMinNS = 60 * 1e6
278278

279279
// osRelax is called by the scheduler when transitioning to and from
280280
// all Ps being idle.

src/runtime/proc.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3808,22 +3808,23 @@ func sysmon() {
38083808
if scavengelimit < forcegcperiod {
38093809
maxsleep = scavengelimit / 2
38103810
}
3811-
if osRelaxDelay > 0 {
3812-
// Wait before osRelaxing in
3813-
// case something happens soon.
3814-
sleep1 := int64(osRelaxDelay)
3815-
if sleep1 > maxsleep {
3816-
sleep1 = maxsleep
3817-
}
3818-
if notetsleep(&sched.sysmonnote, sleep1) {
3819-
maxsleep = 0
3820-
} else {
3821-
maxsleep -= sleep1
3811+
shouldRelax := true
3812+
if osRelaxMinNS > 0 {
3813+
lock(&timers.lock)
3814+
if timers.sleeping {
3815+
now := nanotime()
3816+
next := timers.sleepUntil
3817+
if next-now < osRelaxMinNS {
3818+
shouldRelax = false
3819+
}
38223820
}
3821+
unlock(&timers.lock)
38233822
}
3824-
if maxsleep > 0 {
3823+
if shouldRelax {
38253824
osRelax(true)
3826-
notetsleep(&sched.sysmonnote, maxsleep)
3825+
}
3826+
notetsleep(&sched.sysmonnote, maxsleep)
3827+
if shouldRelax {
38273828
osRelax(false)
38283829
}
38293830
lock(&sched.lock)

src/runtime/relax_stub.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
package runtime
88

9-
// osRelaxDelay is the number of nanoseconds of idleness to tolerate
10-
// before performing an osRelax. Since osRelax may reduce the
9+
// osRelaxMinNS is the number of nanoseconds of idleness to tolerate
10+
// without performing an osRelax. Since osRelax may reduce the
1111
// precision of timers, this should be enough larger than the relaxed
1212
// timer precision to keep the timer error acceptable.
13-
const osRelaxDelay = 0
13+
const osRelaxMinNS = 0
1414

1515
// osRelax is called by the scheduler when transitioning to and from
1616
// all Ps being idle.

src/runtime/time.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var timers struct {
3131
created bool
3232
sleeping bool
3333
rescheduling bool
34+
sleepUntil int64
3435
waitnote note
3536
t []*timer
3637
}
@@ -209,6 +210,7 @@ func timerproc() {
209210
}
210211
// At least one timer pending. Sleep until then.
211212
timers.sleeping = true
213+
timers.sleepUntil = now + delta
212214
noteclear(&timers.waitnote)
213215
unlock(&timers.lock)
214216
notetsleepg(&timers.waitnote, delta)

0 commit comments

Comments
 (0)