-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
runtime: use monotonic time on netbsd #6007
Comments
Run this program package main import ( "fmt" "time" ) func main() { for { fmt.Println(<-time.After(time.Second)) } } and watch it outputs new line to stdout once every second. While the program runs, change your system time to 1 minute back (whatever your current time is minus 1 minute). I use "date" command on linux for that. Watch running program output stops. Should it? Shouldn't it? Alex |
Hi, Here's a go-nuts thread about this exact same issue that hit me in the face yesterday: https://groups.google.com/forum/#!topic/golang-nuts/mUOr4UvsYOY The issue is that any pending ticker will get ruined during an OS time update. E.g. as in the above examples, you start a ticker for 1 secs, set back the OS timer a few hours, and the ticker will never fire (at least not until the OS time reaches the original ticker time). And to give you two real-world examples when this happens: daylight saving (OS updates the date, all tickers pause for an hour). The other is what I got hit with: you boot up the OS, automatically start a Go program, and after a while the clock syncs up and all tickers within the program get corrupted (and this is what actually happens on Google Compute Engine VMs). Cheers, Peter |
The issues in #7 looks WorksAsExpected/Unfortunate, because time operates with real time FWIW. Which is, in my opinion, a design bug, but it is the way it is. This should be solved as part of a more serious changes, there is a discussion on goleng-dev about monotonic clocks. Is it the case that when you set time a minute back, timers stop ticking at all (no ticks after 5 minutes)? This would be a bug. |
There's no magic bullet here. If we use wall time we get weirdness like this when the computer's reported wall time jumps around. If we use some other kind of monotonic "time since boot" time, then things like: t := time.Now() time.Sleep(10*time.Minute) fmt.Println(time.Since(t)) can literally print any value, something arbitrarily far from 10 minutes, even a negative number. I don't think there's anything we can do here that is significantly better than what we have. Status changed to Unfortunate. |
This same issue (wall clock vs monotonic clock) caused real problems at my previous embedded systems job (using C, not Go :-). I think it's a serious issue and should not be taken lightly. Currently, it looks like nanotime() and now() are aliases to each other. My armchair layman's thought is to keep now() functionally the same (i.e. it returns wall time) and have nanotime() use a monotonic clock instead. I'd try it myself except that the relevant bits are in assembly and I haven't wrapped my head around it yet. Considering two core devs have called this issue "Unfortunate", I must be missing something though. |
I meant that is's more WorksAsExpected, because it's the current documented semantics, we can not just change it. However, there are things we can do about it. If you want to blink a window every second, check email every minute, or timeout idle tcp connection after 5 min, then you pretty much do not care about the output of: t := time.Now() time.Sleep(10*time.Minute) fmt.Println(time.Since(t)) You just want timers against monotonic time. In the end, the following code can work perfectly reasonably (well, hibernation aside): t := time.MonoNow() time.MonoSleep(10*time.Minute) fmt.Println(time.MonoSince(t)) Currently we do strange wtfs like timing out tcp connections based on real time... |
It may be possible to make all the relative APIs - After, Sleep, Tick, Ticker, and Timer - use durations against 'monotonic time'. The package net timeouts could do the same internally. However, neither will happen for Go 1.2. The real WTF here is that there are still systems that cannot keep accurate time and have giant backward or forward time jumps in their real time. Come on, guys. It's 2013. Labels changed: added go1.3, removed go1.2maybe. Status changed to Thinking. |
> The real WTF here is that there are still systems that cannot keep accurate time and have giant backward or forward time jumps in their real time. This is not an issue. It is the same on good OSes as well. If you came from server land, you can think that real time==monotonic time. But this is absolutely not true in desktop environment (and there are still bad administrators and so on). On the golang-dev thread I've described some examples when real time changes +/-24h several times a day. For some period of time I was periodically changing real time on my desktop +/-3 *years* to trick some software. Do NOT think of real time as of something related to monotonic time whatever OS you have. For the purpose of correctness, real time must be considered as random number generator. This is expected that if you want to schedule some activity every (realtime) midnight, it will behave weirdly in such environment (and there is nothing we can do with it). But it's a failure on our side, if all Go software suddenly crashes/timeouts/hangs when a user changes real time to +/-12h. And this is what happens now (all network connections suddenly timeout or never timeout; time.Ticker(time.Second) stops ticking, etc). |
> it's the current documented semantics, we can not just change it. Where is it documented? I do not see anything in the documentation for Duration (or the functions that use it) that indicates it is used as a delta for wall time. If anything, I think changing Duration-related functions to use a monotonic clock would make it more accurate and less surprising with its current documentation. > The real WTF here is that there are still systems that cannot keep accurate time and have giant backward or forward time jumps in their real time. Not all devices have the luxury of saving the time and asking the Internet. At my previous job, I worked on an embedded system that did not save time across power cycles because it was small and didn't have a battery. An external source would eventually push a time to my device sometime after boot. The time updates would not necessarily come right away, and sometimes the time would jump around multiple times (and by large magnitudes) depending on the kind of testing the systems guys were doing. The software had to use monotonic clocks in order to be robust and not break during wall time changes. |
> Where is it documented? I have not looked at the documentation, but: 1. it is how it works now, so people may be relying on it (even if it's not explicitly documented). 2. Go does not have a notion of monotonic time, so it's reasonable to infer that everything relates to real time. E.g. Russ's example in #10 should print something close to 10min, rather than arbitrary value. Probably we may try to change it, but we must be very careful. To make it clear, I agree that it's not for Go1.2. This requires very serious changes. On second though (I think I already described it in the golang-dev thread), time.Sleep(10*time.Minute) can not possibly reliably sleep till some real time instant (e.g. midnight). A function that sleeps till some real time instant must necessary accept time instant (i.e. time.Time), otherwise it's broken if time change happens before runtime converts time.Duration to time.Time. So, Russ, your example in #10 prints random value even now. And of course time can be changes after time.Sleep returns, but before you query time.Now the second time. >The software had to use monotonic clocks in order to be robust and not break during wall time changes. This is a good idea in all other contexts as well. |
I've created a naive fix for linux_amd64. I can now run the snippet from comment #6 and the program won't lose its marbles after changing the host's calendar time. The changes are small enough that they'll hopefully be self-explanatory. I wrote what I thought was the simplest way - not necessarily the best way - just to get others thinking about it. |
I suppose a link to the changes would help: https://github.com/jayschwa/golang/compare/master...monotonic |
rsc: to add on to what dvyukov said in #14, there is a very common case where this happens all the time. Specifically, if you put your phone/laptop in airplane mode, then get on a plane, and fly far enough. When you land and resync your clock, it can jump around quite significantly. I once had a user file a bug report on an iOS app with this exact issue. |
There is https://golang.org/cl/53010043/ in progress |
This issue was updated by revision 86c976f. LGTM=dvyukov, rsc R=golang-codereviews, dvyukov, alex.brainman, stephen.gutekanst, dave, rsc, mikioh.mikioh CC=golang-codereviews https://golang.org/cl/53010043 Committer: Russ Cox |
This issue was updated by revision 7206f50. LGTM=dvyukov R=golang-codereviews, dvyukov CC=golang-codereviews https://golang.org/cl/67730048 |
This issue was updated by revision 36013e4. LGTM=minux.ma R=golang-codereviews, minux.ma, bradfitz CC=golang-codereviews https://golang.org/cl/68690043 |
This issue was updated by revision 3734663. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/68460044 |
This issue was updated by revision b4dc91e. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/69040045 |
CL https://golang.org/cl/108700045 mentions this issue. |
Windows can be removed from the issue title. It was implemented in 74b62b4. |
Change https://golang.org/cl/81135 mentions this issue: |
Change https://golang.org/cl/81715 mentions this issue: |
This change updates runtime.semasleep to no longer call runtime.nanotime and instead calls lwp_park with a duration to sleep relative to the monotonic clock, so the nanotime is never called. (This requires updating to a newer version of the lwp_park system call, which is safe, because Go 1.10 will require the unreleased NetBSD 8+ anyway) Additionally, this change makes the nanotime function use the monotonic clock for netbsd/arm, which was forgotten from https://golang.org/cl/81135 which updated netbsd/amd64 and netbsd/386. Because semasleep previously depended on nanotime, the past few days of netbsd have likely been unstable because lwp_park was then mixing the monotonic and wall clocks. After this CL, lwp_park no longer depends on nanotime. Original patch submitted at: https://www.netbsd.org/~christos/go-lwp-park-clock-monotonic.diff This commit message (any any mistakes therein) were written by Brad Fitzpatrick. (Brad migrated the patch to Gerrit and checked CLAs) Updates #6007 Fixes #22968 Also updates netbsd/arm to use monotonic time for Change-Id: If77ef7dc610b3025831d84cdfadfbbba2c52acb2 Reviewed-on: https://go-review.googlesource.com/81715 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Update golang#6007. LGTM=minux, dvyukov R=golang-codereviews, dvyukov, patrick, aram.h, minux CC=golang-codereviews https://golang.org/cl/108700045
Update golang#6007. LGTM=minux, dvyukov R=golang-codereviews, dvyukov, patrick, aram.h, minux CC=golang-codereviews https://golang.org/cl/108700045
by gmale120:
The text was updated successfully, but these errors were encountered: