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

runtime: on PPC64x, arm64, mips64x time.Now precision is in microseconds, not nanoseconds #11222

Closed
laboger opened this issue Jun 15, 2015 · 16 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done. OS-Linux
Milestone

Comments

@laboger
Copy link
Contributor

laboger commented Jun 15, 2015

libgo/runtime/go-nanotime.c calls gettimeofday which only provides microsecond precision, not the nanosecond precision that is documented for Time.

Here is a testcase that demonstrates the problem. I built it using gccgo from the latest gcc5 branch, and I can see the libgo code for go-nanotime.c is the same in trunk so would expect the same behavior there. The problem occurs on ppc64le and x86 with gccgo; did not try ppc64 but would expect that behavior there too. Problem does not occur with golang.

package main

import (
        "fmt"
        "time"
)

const (
        defaultTimeOut = 30
)

func abort(start time.Time, timeOff time.Duration) bool {
        since := time.Since(start)
        now := time.Now()
        fmt.Printf("start: %s since: %d now: %s\n", start.String(), since, now.String())
        return timeOff.Nanoseconds()+time.Since(start).Nanoseconds() > (time.Duration(defaultTimeOut) * time.Second).Nanoseconds()
}

func main() {
        cases := []struct {
                timeOff  time.Duration
                expAbort bool
        }{
                {time.Duration(1), false},
                {time.Duration(2), false},
                {time.Duration(10), false},
                {time.Duration(30), true},
                {time.Duration(40), true},
        }

        for _, c := range cases {
                s := c.timeOff * time.Second
                if a := abort(time.Now(), s); a != c.expAbort {
                        fmt.Printf("Duration %v, expected %v, was %v\n", c.timeOff, s, a)
                }
        }

}
start: 2015-06-15 13:09:04.675845 -0500 CDT since: 7000 now: 2015-06-15 13:09:04.675856 -0500 CDT
start: 2015-06-15 13:09:04.676307 -0500 CDT since: 0 now: 2015-06-15 13:09:04.676307 -0500 CDT
start: 2015-06-15 13:09:04.67633 -0500 CDT since: 0 now: 2015-06-15 13:09:04.676331 -0500 CDT
start: 2015-06-15 13:09:04.676351 -0500 CDT since: 1000 now: 2015-06-15 13:09:04.676352 -0500 CDT
start: 2015-06-15 13:09:04.676373 -0500 CDT since: 0 now: 2015-06-15 13:09:04.676374 -0500 CDT

The value of 0 occurs intermittently for the "since" value in the output due to the lack of precision.

Could clock_gettime be called instead to get nanosecond precision?

@laboger
Copy link
Contributor Author

laboger commented Nov 19, 2015

Originally I opened this as gccgo only, but now I see it applies to golang as well. The time.now function in sys_linux_ppc64x.s is calling gettimeofday which only has microsecond precision instead of nanosecond precision like Time is supposed.

ianlancetaylor added a commit to golang/gofrontend that referenced this issue Nov 21, 2015
Fetch the current time in nanoseconds, not microseconds, by using
clock_gettime rather than gettimeofday.

Update golang/go#11222.

Fixes https://gcc.gnu.org/PR66574.

Change-Id: Ia9596f6a4b301ac0aa3b311e91106d0b9952ec3f
Reviewed-on: https://go-review.googlesource.com/17156
Reviewed-by: Ian Lance Taylor <iant@golang.org>
@ianlancetaylor ianlancetaylor changed the title gccgo, time: time.Now() precision is in microseconds, not nanoseconds runtime: on PPC64x, arm64, mips64x time.Now precision is in microseconds, not nanoseconds Nov 21, 2015
@ianlancetaylor
Copy link
Contributor

This is now fixed on gccgo mainline but the problem remains for the GNU/Linux targets arm64, mips64x, ppc64x. They should call clock_gettime, not gettimeday.

@ianlancetaylor ianlancetaylor modified the milestones: Go1.6, Gccgo Nov 21, 2015
@rsc rsc modified the milestones: Unplanned, Go1.6 Dec 5, 2015
@tophj-ibm
Copy link

As of go1.7rc3, I'm still seeing this as an issue, at least on ppc64le. Running the same test as above gives.

start: 2016-07-27 14:21:51.111599 +0000 UTC since: 0 now: 2016-07-27 14:21:51.1116 +0000 UTC
start: 2016-07-27 14:21:51.112122 +0000 UTC since: 1000 now: 2016-07-27 14:21:51.112124 +0000 UTC
start: 2016-07-27 14:21:51.112142 +0000 UTC since: 1000 now: 2016-07-27 14:21:51.112144 +0000 UTC
start: 2016-07-27 14:21:51.112162 +0000 UTC since: 260000 now: 2016-07-27 14:21:51.112423 +0000 UTC
start: 2016-07-27 14:21:51.112441 +0000 UTC since: 1000 now: 2016-07-27 14:21:51.112443 +0000 UTC

@mwhudson
Copy link
Contributor

The bug is still open so that's not very surprising?

@laboger
Copy link
Contributor Author

laboger commented Aug 2, 2016

We're going to look into fixing this for ppc64x. Just wondering if there was any additional information to share on this. We don't know if it is only wrong for ppc64x or still incorrect on the other platforms mentioned above.

ceseo added a commit to ceseo/go that referenced this issue Aug 10, 2016
Fetch the current time in nanoseconds, not microseconds, by using
clock_gettime rather than gettimeofday.

Fixes golang#11222
@gopherbot
Copy link
Contributor

CL https://golang.org/cl/26790 mentions this issue.

@bradfitz bradfitz modified the milestones: Go1.8, Unplanned Aug 10, 2016
gopherbot pushed a commit that referenced this issue Aug 23, 2016
Fetch the current time in nanoseconds, not microseconds, by using
clock_gettime rather than gettimeofday.

Updates #11222

Change-Id: I1c2c1b88f80ae82002518359436e19099061c6fb
Reviewed-on: https://go-review.googlesource.com/26790
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
Reviewed-by: Minux Ma <minux@golang.org>
ceseo added a commit to powertechpreview/go that referenced this issue Aug 23, 2016
Fetch the current time in nanoseconds, not microseconds, by using
clock_gettime rather than gettimeofday.

Updates golang#11222

Change-Id: I1c2c1b88f80ae82002518359436e19099061c6fb
ceseo added a commit to powertechpreview/go that referenced this issue Aug 23, 2016
Fetch the current time in nanoseconds, not microseconds, by using
clock_gettime rather than gettimeofday.

Updates golang#11222

Change-Id: I1c2c1b88f80ae82002518359436e19099061c6fb
@vogtd
Copy link
Contributor

vogtd commented Aug 23, 2016

I don't actually get where it is required that timestamps in Time format returned by time.Now() have actually nanosecond precision. Certainly not here:
https://golang.org/pkg/time/#Now

@bradfitz
Copy link
Contributor

@vogtd, it's not required. It's nice.

@clnperez
Copy link

And also would be consistent between platforms. 👍

@vogtd
Copy link
Contributor

vogtd commented Aug 23, 2016

All right, so it's rather an improvement request than a bugreport.

I'm a bit lost about about the status regarding s390[x]:

  • Is it already fixed in Golang for s390[x](or was it an issue there at all)?
  • If it's been fixed already, will that fix trickle down automatically into the Gofrontend or should I make a patch for that?

@billotosyr
Copy link

It is not yet fixed in golang for s390x.

@ianlancetaylor
Copy link
Contributor

@vogtd The gofrontend used by gccgo uses different code to get the time. It already returns nanosecond precision for time.Now on s390 (by calling clock_gettime(CLOCK_REALTIME, ...)).

@justincormack
Copy link

@ianlancetaylor interested in the case of s390x on 1.7 ie not using gccgo, as that is what we are using now.

@gopherbot
Copy link
Contributor

CL https://golang.org/cl/27710 mentions this issue.

gopherbot pushed a commit that referenced this issue Aug 25, 2016
This should improve the precision of time.now() from microseconds
to nanoseconds.

Also, modify runtime.nanotime to keep it consistent with cleanup
done to time.now.

Updates #11222 for s390x.

Change-Id: I27864115ea1fee7299360d9003cd3a8355f624d3
Reviewed-on: https://go-review.googlesource.com/27710
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@quentinmit quentinmit added the NeedsFix The path to resolution is known, but the work has not been done. label Oct 11, 2016
@rsc
Copy link
Contributor

rsc commented Oct 27, 2016

Ian says gccgo is already OK. I assume it uses clock_gettime(CLOCK_REALTIME) always.

As for the gc toolchain, I surveyed all the time.now implementations in runtime/*.s:

  • darwin/386: kernel time equation + RDTSC, fallback to gettimeofday (microsecond)
  • darwin/amd64: kernel time equation + RDTSC, fallback to gettimeofday (microsecond)
  • darwin/arm: gettimeofday (microsecond)
  • darwin/arm64: gettimeofday (microsecond)
  • dragonfly/amd64: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • freebsd/386: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • freebsd/amd64: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • freebsd/arm: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • linux/386: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • linux/amd64: vdso_clock_gettime(CLOCK_REALTIME) (nanosecond) if available, or else vdso_gettimeofday (microsecond)
  • linux/arm: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • linux/arm64: gettimeofday (microsecond)
  • linux/mips64x: gettimeofday (microsecond)
  • linux/ppc64x: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • linux/s390x: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • nacl/386: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • nacl/amd64p32: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • nacl/arm: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • netbsd/386: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • netbsd/amd64: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • netbsd/arm: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • openbsd/386: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • openbsd/amd64: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • openbsd/arm: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • plan9/386: nsec (nanosecond)
  • plan9/amd64: nsec (nanosecond)
  • plan9/arm: nsec (nanosecond)
  • solaris/amd64: clock_gettime(CLOCK_REALTIME) (nanosecond)
  • windows/386: read from kernel memory (100 nanosecond)
  • windows/amd64: read from kernel memory (100 nanosecond)

On OS X, there is no nanosecond system call. If the kernel equation is not available, the only fallback is gettimeofday (microseconds).

On Linux, arm64 and mips64x should use clock_gettime(CLOCK_REALTIME). That's easy since there is assembly for clock_gettime(CLOCK_MONOTONIC) already that I can copy. I sent CL 32177 for those.

Otherwise it looks like everything is fetching nanosecond precision already.

Of course, precision does not imply accuracy. I doubt that windows is updating the kernel memory copy of the current time every 100ns, for example, and invoking a clock_gettime(CLOCK_REALTIME) system call to fetch the time at nanosecond accuracy may itself take 10s or 100s of nanoseconds. In fact precision does not even imply precision. There's no guarantee that the kernel is even computing nanoseconds during the system call. It might always come back with only microseconds, for example. But that's not Go's problem.

@gopherbot
Copy link
Contributor

CL https://golang.org/cl/32177 mentions this issue.

@golang golang locked and limited conversation to collaborators Oct 27, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done. OS-Linux
Projects
None yet
Development

No branches or pull requests