]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: reduce Windows timer resolution when idle
authorAustin Clements <austin@google.com>
Tue, 21 Mar 2017 20:45:12 +0000 (16:45 -0400)
committerAustin Clements <austin@google.com>
Sat, 29 Apr 2017 04:15:49 +0000 (04:15 +0000)
Currently Go sets the system-wide timer resolution to 1ms the whole
time it's running. This has negative affects on system performance and
power consumption. Unfortunately, simply reducing the timer resolution
to the default 15ms interferes with several sleeps in the runtime
itself, including sysmon's ability to interrupt goroutines.

This commit takes a hybrid approach: it only reduces the timer
resolution when the Go process is entirely idle. When the process is
idle, nothing needs a high resolution timer. When the process is
non-idle, it's already consuming CPU so it doesn't really matter if
the OS also takes timer interrupts more frequently.

Updates #8687.

Change-Id: I0652564b4a36d61a80e045040094a39c19da3b06
Reviewed-on: https://go-review.googlesource.com/38403
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
src/runtime/os_windows.go
src/runtime/proc.go
src/runtime/relax_stub.go [new file with mode: 0644]

index 672cc100d5cf4ca6483d6753b89f89a113b59f5c..3df3d28ed08e7aaac89cc70332ca1e4c54a4f7bb 100644 (file)
@@ -50,6 +50,7 @@ const (
 //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
 //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
 //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
+//go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll"
 
 type stdFunction unsafe.Pointer
 
@@ -96,6 +97,7 @@ var (
        _WriteConsoleW,
        _WriteFile,
        _timeBeginPeriod,
+       _timeEndPeriod,
        _ stdFunction
 
        // Following syscalls are only available on some Windows PCs.
@@ -268,6 +270,21 @@ var useLoadLibraryEx bool
 
 var timeBeginPeriodRetValue uint32
 
+// osRelax is called by the scheduler when transitioning to and from
+// all Ps being idle.
+//
+// On Windows, it adjusts the system-wide timer resolution. Go needs a
+// high resolution timer while running and there's little extra cost
+// if we're already using the CPU, but if all Ps are idle there's no
+// need to consume extra power to drive the high-res timer.
+func osRelax(relax bool) uint32 {
+       if relax {
+               return uint32(stdcall1(_timeEndPeriod, 1))
+       } else {
+               return uint32(stdcall1(_timeBeginPeriod, 1))
+       }
+}
+
 func osinit() {
        asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
        usleep2Addr = unsafe.Pointer(funcPC(usleep2))
@@ -287,7 +304,7 @@ func osinit() {
 
        stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
 
-       timeBeginPeriodRetValue = uint32(stdcall1(_timeBeginPeriod, 1))
+       timeBeginPeriodRetValue = osRelax(false)
 
        ncpu = getproccount()
 
index dae8f135bcd904ec6f293e8a4d451018f0b9b436..7d6b89016a6052451e938f2207be5438fb07d085 100644 (file)
@@ -3751,7 +3751,9 @@ func sysmon() {
                                if scavengelimit < forcegcperiod {
                                        maxsleep = scavengelimit / 2
                                }
+                               osRelax(true)
                                notetsleep(&sched.sysmonnote, maxsleep)
+                               osRelax(false)
                                lock(&sched.lock)
                                atomic.Store(&sched.sysmonwait, 0)
                                noteclear(&sched.sysmonnote)
diff --git a/src/runtime/relax_stub.go b/src/runtime/relax_stub.go
new file mode 100644 (file)
index 0000000..78c3273
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package runtime
+
+// osRelax is called by the scheduler when transitioning to and from
+// all Ps being idle.
+func osRelax(relax bool) {}