]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: delay before osRelaxing
authorAustin Clements <austin@google.com>
Fri, 7 Jul 2017 16:03:22 +0000 (12:03 -0400)
committerAustin Clements <austin@google.com>
Fri, 7 Jul 2017 21:02:40 +0000 (21:02 +0000)
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: Brad Fitzpatrick <bradfitz@golang.org>
src/runtime/os_windows.go
src/runtime/proc.go
src/runtime/relax_stub.go

index 72b57ad7dc39e780aff62b610d1200080d31fd31..dcb232a995225fe845444f7c1e398baa9afd08f1 100644 (file)
@@ -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.
 //
index 9f8729a19b3d1c0544c0e6c1352de5ab0e58d771..0219d2d77ddcd2d8d67a2527fbb48c05edc81853 100644 (file)
@@ -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)
index 78c32736d76d3e59ceb6cfa9e408516a667c5a23..648788118e84c4520cf33b68c065626064abdf4a 100644 (file)
@@ -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) {}