]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use next timer to decide whether to relax
authorAustin Clements <austin@google.com>
Fri, 7 Jul 2017 18:58:55 +0000 (14:58 -0400)
committerAustin Clements <austin@google.com>
Fri, 7 Jul 2017 21:22:31 +0000 (21:22 +0000)
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>
src/runtime/os_windows.go
src/runtime/proc.go
src/runtime/relax_stub.go
src/runtime/time.go

index dcb232a995225fe845444f7c1e398baa9afd08f1..60fc8e590bc0becb833dfb550d19f19842e977d1 100644 (file)
@@ -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.
index 0219d2d77ddcd2d8d67a2527fbb48c05edc81853..4f61f6164b8691a1abe80b1b9d7f248d59e8fff2 100644 (file)
@@ -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)
index 648788118e84c4520cf33b68c065626064abdf4a..81ed1291b8b812435414ca254d32bbfa264e70d1 100644 (file)
@@ -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.
index 88ab8b9c02fa397b513dec15552bf1b835cce395..abf200d7d3f7c825f6b5ba21f7c26f9718850baf 100644 (file)
@@ -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)