Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time: Sleep(1 * time.Nanosecond) pauses at least 1.9ms on Windows 10 or Windows 7 #29485

Closed
destinysync opened this issue Dec 31, 2018 · 17 comments
Closed

Comments

@destinysync
Copy link

@destinysync destinysync commented Dec 31, 2018

What version of Go are you using (go version)?

go version go1.11.4 windows/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\admin\AppData\Local\go-build
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\admin\go
set GOPROXY=
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\admin\AppData\Local\Temp\go-build968081038=/tmp/go-build -gno-record-gcc-switches

What did you do?

https://play.golang.org/p/zbe1kiCREc0

time.Sleep function works correctly on Go Playground and Ubuntu desktop 18.04, but when on Windows 10 or Windows 7, time.Sleep pauses at least 1.9ms

What did you expect to see?

1ns

What did you see instead?

1.9951ms

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Dec 31, 2018

@40345839668 Most people who use this issue tracker can not read Turkish. Please comment in English. Thanks.

@destinysync A sleep of one nanosecond is unlikely to work on any system. A sleep is always going to be limited by the clock frequency of the system.

@ianlancetaylor ianlancetaylor changed the title time.Sleep(1 * time.Nanosecond) pauses at least 1.9ms on Windows 10 or Windows 7 time: Sleep(1 * time.Nanosecond) pauses at least 1.9ms on Windows 10 or Windows 7 Dec 31, 2018
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Dec 31, 2018
@destinysync
Copy link
Author

@destinysync destinysync commented Jan 1, 2019

@ianlancetaylor , not only 1 * time.Nanosecond, any time.Sleep duration less than 1.9ms, e.g., 500 * time.Microsecond, 1 * time.Millisecond, pauses at least 1.9ms.

My computer's CPU is Intel i5 8250U, which has 4 cores, 8 threads, and a max turbo speed of 3.4 GHz, when I tested on the same hardware inside virtual machine with Ubuntu desktop 18.04 operating system , time: Sleep(1 * time.Nanosecond) only pauses 26.079µs, while outside the virtual machine on a Windows 10 system, time: Sleep(1 * time.Nanosecond) pauses 1.9951ms, so the root of the problem might not be hardware related.

the difference between 1.9951ms and 26.079µs does not seem huge on normal occasions, but I am trying to build a reliable protocol on top of UDP, due to 1.9951ms delay per datagram , transferring a file with a size of only 10Mb between a UDP client and a UDP server on the same machine takes more than 15 seconds, in comparison, TCP finishes the task within 0.5 seconds.

@alexbrainman
Copy link
Member

@alexbrainman alexbrainman commented Jan 1, 2019

when on Windows 10 or Windows 7, time.Sleep pauses at least 1.9ms

This is what I see on my Windows computer too.

1ms sleep for time.Sleep(time.Nanosecond) sounds about right for current Windows time.Sleep implementation. If you have suggestion on how to improve the code, you are most welcome.

Alex

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 1, 2019

I was imprecise in referring to the clock frequency. I didn't mean the frequency of the processor. I meant the frequency of the operating system: how often it does timer interrupts.

It's entirely possible that there is something to be fixed here. But time.Sleep(time.Nanosecond) is unlikely to ever work as you expect. You should use a different mechanism. For a nanosecond delay a busy wait is appropriate. In fact just fetching the current time will most likely take more than one nanosecond.

@networkimprov
Copy link

@networkimprov networkimprov commented Jan 1, 2019

@destinysync what does this yield?

a := time.Now()
b := <-time.After(1*time.Nanosecond)
fmt.Println(b.Sub(a))
@destinysync
Copy link
Author

@destinysync destinysync commented Jan 1, 2019

@networkimprov

	for i:=0; i< 10; i++ {
		a := time.Now()
		b := <-time.After(1*time.Nanosecond)
		fmt.Println(b.Sub(a))
	}

yields:

2.0014ms
1.9888ms
1.9951ms
1.9934ms
1.9945ms
1.9945ms
1.9951ms
1.9951ms
1.9945ms
1.9946ms
@davecheney
Copy link
Contributor

@davecheney davecheney commented Jan 2, 2019

@destinysync time.Sleep is not specified to sleep for precisely the duration requested, it is specified to sleep for at least the duration requested. The delta between the minimum--the duration you requested--and the observed is implementation and operating system dependent. I don't think there is anything to be fixed here.

@networkimprov
Copy link

@networkimprov networkimprov commented Jan 2, 2019

That shows a possible resolution of 100ns (0.0001ms). Go may be calling an obsolete Windows API which doesn't support that.

Windows 7 supports 100ns resolution timers:
https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-setwaitabletimerex

EDIT: Go uses SetWaitableTimer for the profiler.

Windows 2000 supports 100ns resolution sleep:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-kedelayexecutionthread

EDIT: A thread does not resume when the above call's Interval has elapsed; it becomes eligible for execution.

@dominikh
Copy link
Member

@dominikh dominikh commented Jan 2, 2019

Related: #8687

@networkimprov
Copy link

@networkimprov networkimprov commented Jan 2, 2019

@destinysync I suggest revising this issue to cover time.After/NewTimer since its precision is probably more important than time.Sleep. And time.After/AfterFunc is the right tool for protocol pauses.

EDIT: Possibly related: #17696

@networkimprov
Copy link

@networkimprov networkimprov commented Jan 4, 2019

@alexbrainman @destinysync I suggested changing this issue to be about time.After/NewTimer. If you prefer, I'll open a separate issue regarding resolution of time.NewTimer on Windows; please let me know!

@alexbrainman
Copy link
Member

@alexbrainman alexbrainman commented Jan 5, 2019

I suggested changing this issue to be about time.After/NewTimer. If you prefer, I'll open a separate issue regarding resolution of time.NewTimer on Windows; please let me know!

I do not know how to fix this issue. Regardless of what description of this issue is.

Alex

@networkimprov
Copy link

@networkimprov networkimprov commented Jan 8, 2019

@alexbrainman @aclements

SetWaitableTimer claims 100ns resolution; Go currently uses it in the profiler but not elsewhere (that I could find). Wouldn't that improve time.NewTimer/After over its current ~2ms resolution?

https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-setwaitabletimerex

EDIT: hardware background...
https://en.wikipedia.org/wiki/High_Precision_Event_Timer

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Dec 13, 2019

Currently time.Sleep operates at the scheduling frequency of the operating system. It is not a high precision timer. On my laptop time.Sleep(1 * time.Nanosecond) sleeps for over 500 nanoseconds. That's quite a bit better than Windows, but still two orders of magnitude larger than the requested sleep.

The function is documented as "Sleep pauses the current goroutine for at least the duration d." While perhaps it would useful to provide high precision timers in Go, the mechanism will not be time.Sleep. I'm going to close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants
@davecheney @dominikh @networkimprov @ianlancetaylor @alexbrainman @destinysync and others
You can’t perform that action at this time.