runtime: use clock_gettime to get ns resolution for time.now & runtime.nanotime
For Linux/{386,arm}, FreeBSD/{386,amd64,arm}, NetBSD/{386,amd64}, OpenBSD/{386,amd64}.
Note: our Darwin implementation already has ns resolution.
Linux/386 (Core i7-2600 @ 3.40GHz, kernel 3.5.2-gentoo)
benchmark old ns/op new ns/op delta
BenchmarkNow 110 118 +7.27%
Linux/ARM (ARM Cortex-A8 @ 800MHz, kernel 2.6.32.28 android)
benchmark old ns/op new ns/op delta
BenchmarkNow 625 542 -13.28%
Linux/ARM (ARM Cortex-A9 @ 1GHz, Pandaboard)
benchmark old ns/op new ns/op delta
BenchmarkNow 992 909 -8.37%
FreeBSD 9-REL-p1/amd64 (Dell R610 Server with Xeon X5650 @ 2.67GHz)
benchmark old ns/op new ns/op delta
BenchmarkNow 699 695 -0.57%
FreeBSD 9-REL-p1/amd64 (Atom D525 @ 1.80GHz)
benchmark old ns/op new ns/op delta
BenchmarkNow 1553 1658 +6.76%
OpenBSD/amd64 (Dell E6410 with i5 CPU M 540 @ 2.53GHz)
benchmark old ns/op new ns/op delta
BenchmarkNow 1262 1236 -2.06%
OpenBSD/i386 (Asus eeePC 701 with Intel Celeron M 900MHz - locked to 631MHz)
benchmark old ns/op new ns/op delta
BenchmarkNow 5089 5043 -0.90%
NetBSD/i386 (VMware VM with Core i5 CPU @ 2.7GHz)
benchmark old ns/op new ns/op delta
BenchmarkNow 277 278 +0.36%
NetBSD/amd64 (VMware VM with Core i5 CPU @ 2.7Ghz)
benchmark old ns/op new ns/op delta
BenchmarkNow 103 105 +1.94%
Thanks Maxim Khitrov, Joel Sing, and Dave Cheney for providing benchmark data.
R=jsing, dave, rsc
CC=golang-dev
https://golang.org/cl/6820120
diff --git a/doc/go1.1.html b/doc/go1.1.html
index d350303..47a25b6 100644
--- a/doc/go1.1.html
+++ b/doc/go1.1.html
@@ -94,10 +94,10 @@
<h3 id="time">time</h3>
<p>
-On Linux, previous versions of the time package returned times with
-microsecond precision. The Go 1.1 implementation of time on Linux now returns times with
-nanosecond precision. Code may exist that expects to be able to store
-such a time in an external format with only microsecond precision,
+On FreeBSD, Linux, NetBSD, OS X and OpenBSD, previous versions of the time package
+returned times with microsecond precision. The Go 1.1 implementation of time on these
+systems now returns times with nanosecond precision. Code may exist that expects to be
+able to store such a time in an external format with only microsecond precision,
read it back, and recover exactly the same time instant.
In Go 1.1 the same time will not be recovered, since the external storage
will have discarded nanoseconds.
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index 9049f1e..a30c7ba 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -116,40 +116,38 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- MOVL $116, AX
+ MOVL $232, AX
LEAL 12(SP), BX
- MOVL BX, 4(SP)
- MOVL $0, 8(SP)
+ MOVL $0, 4(SP)
+ MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // usec
+ MOVL 16(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
MOVL AX, sec+0(FP)
MOVL $0, sec+4(FP)
- IMULL $1000, BX
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), 7, $32
- MOVL $116, AX
+ MOVL $232, AX
LEAL 12(SP), BX
- MOVL BX, 4(SP)
- MOVL $0, 8(SP)
+ MOVL $0, 4(SP)
+ MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // usec
+ MOVL 16(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
// convert to DX:AX nsec
MOVL $1000000000, CX
MULL CX
- IMULL $1000, BX
ADDL BX, AX
ADCL $0, DX
-
+
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
MOVL DX, 4(DI)
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 6c52dfa..7b13591 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -94,31 +94,29 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- MOVL $116, AX
- LEAQ 8(SP), DI
- MOVQ $0, SI
+ MOVL $232, AX
+ MOVQ $0, DI
+ LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVQ 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
MOVQ AX, sec+0(FP)
- IMULQ $1000, DX
MOVL DX, nsec+8(FP)
RET
TEXT runtime·nanotime(SB), 7, $32
- MOVL $116, AX
- LEAQ 8(SP), DI
- MOVQ $0, SI
+ MOVL $232, AX
+ MOVQ $0, DI
+ LEAQ 8(SP), SI
SYSCALL
MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVQ 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
// return nsec in AX
IMULQ $1000000000, AX
- IMULQ $1000, DX
ADDQ DX, AX
RET
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 1edf807..ec8134e 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -86,39 +86,36 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- MOVW $8(R13), R0
- MOVW $0, R1
- SWI $116 // gettimeofday
+ MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $8(R13), R1
+ SWI $232 // clock_gettime
MOVW 8(R13), R0 // sec.low
- MOVW 16(R13), R2 // usec
+ MOVW 12(R13), R1 // sec.high
+ MOVW 16(R13), R2 // nsec
MOVW R0, 0(FP)
- MOVW $0, R1
MOVW R1, 4(FP)
- MOVW $1000, R3
- MUL R3, R2
MOVW R2, 8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), 7, $32
- MOVW $8(R13), R0
- MOVW $0, R1
- SWI $116 // gettimeofday
+ MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $8(R13), R1
+ SWI $232 // clock_gettime
MOVW 8(R13), R0 // sec.low
- MOVW 16(R13), R2 // usec
+ MOVW 12(R13), R4 // sec.high
+ MOVW 16(R13), R2 // nsec
MOVW $1000000000, R3
MULLU R0, R3, (R1, R0)
- MOVW $1000, R3
- MOVW $0, R4
- MUL R3, R2
+ MUL R3, R4
ADD.S R2, R0
ADC R4, R1
-
+
MOVW 0(FP), R3
MOVW R0, 0(R3)
MOVW R1, 4(R3)
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index 28ae37b..b212f80 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -104,40 +104,38 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- MOVL $78, AX // syscall - gettimeofday
- LEAL 8(SP), BX
- MOVL $0, CX
+ MOVL $265, AX // syscall - clock_gettime
+ MOVL $0, BX
+ LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
MOVL 8(SP), AX // sec
- MOVL 12(SP), BX // usec
+ MOVL 12(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
MOVL AX, sec+0(FP)
MOVL $0, sec+4(FP)
- IMULL $1000, BX
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), 7, $32
- MOVL $78, AX // syscall - gettimeofday
- LEAL 8(SP), BX
- MOVL $0, CX
+ MOVL $265, AX // syscall - clock_gettime
+ MOVL $0, BX
+ LEAL 8(SP), CX
MOVL $0, DX
CALL *runtime·_vdso(SB)
MOVL 8(SP), AX // sec
- MOVL 12(SP), BX // usec
+ MOVL 12(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
// convert to DX:AX nsec
MOVL $1000000000, CX
MULL CX
- IMULL $1000, BX
ADDL BX, AX
ADCL $0, DX
-
+
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
MOVL DX, 4(DI)
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 38bcebf..ec5b0ca 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -35,6 +35,7 @@
#define SYS_select (SYS_BASE + 142) // newselect
#define SYS_ugetrlimit (SYS_BASE + 191)
#define SYS_sched_getaffinity (SYS_BASE + 242)
+#define SYS_clock_gettime (SYS_BASE + 263)
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
@@ -155,41 +156,37 @@
RET
TEXT time·now(SB), 7, $32
- MOVW $8(R13), R0 // timeval
- MOVW $0, R1 // zone
- MOVW $SYS_gettimeofday, R7
+ MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $8(R13), R1 // timespec
+ MOVW $SYS_clock_gettime, R7
SWI $0
MOVW 8(R13), R0 // sec
- MOVW 12(R13), R2 // usec
+ MOVW 12(R13), R2 // nsec
MOVW R0, 0(FP)
MOVW $0, R1
MOVW R1, 4(FP)
- MOVW $1000, R3
- MUL R3, R2
MOVW R2, 8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),7,$32
- MOVW $8(R13), R0 // timeval
- MOVW $0, R1 // zone
- MOVW $SYS_gettimeofday, R7
+ MOVW $0, R0 // CLOCK_REALTIME
+ MOVW $8(R13), R1 // timespec
+ MOVW $SYS_clock_gettime, R7
SWI $0
MOVW 8(R13), R0 // sec
- MOVW 12(R13), R2 // usec
+ MOVW 12(R13), R2 // nsec
MOVW $1000000000, R3
MULLU R0, R3, (R1, R0)
- MOVW $1000, R3
MOVW $0, R4
- MUL R3, R2
ADD.S R2, R0
ADC R4, R1
-
+
MOVW 0(FP), R3
MOVW R0, 0(R3)
MOVW R1, 4(R3)
diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s
index 9c88b14..1a4ff95 100644
--- a/src/pkg/runtime/sys_netbsd_386.s
+++ b/src/pkg/runtime/sys_netbsd_386.s
@@ -98,9 +98,9 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
LEAL 12(SP), BX
- MOVL BX, 4(SP) // arg 1 - tp
- MOVL $0, 8(SP) // arg 2 - tzp
- MOVL $418, AX // sys_gettimeofday
+ MOVL $0, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $427, AX // sys_clock_gettime
INT $0x80
MOVL 12(SP), AX // sec - l32
@@ -108,8 +108,7 @@
MOVL 16(SP), AX // sec - h32
MOVL AX, sec+4(FP)
- MOVL 20(SP), BX // usec - should not exceed 999999
- IMULL $1000, BX
+ MOVL 20(SP), BX // nsec
MOVL BX, nsec+8(FP)
RET
@@ -117,9 +116,9 @@
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),7,$32
LEAL 12(SP), BX
- MOVL BX, 4(SP) // arg 1 - tp
- MOVL $0, 8(SP) // arg 2 - tzp
- MOVL $418, AX // sys_gettimeofday
+ MOVL $0, 4(SP) // arg 1 - clock_id
+ MOVL BX, 8(SP) // arg 2 - tp
+ MOVL $427, AX // sys_clock_gettime
INT $0x80
MOVL 16(SP), CX // sec - h32
@@ -129,8 +128,7 @@
MOVL $1000000000, BX
MULL BX // result in dx:ax
- MOVL 20(SP), BX // usec
- IMULL $1000, BX
+ MOVL 20(SP), BX // nsec
ADDL BX, AX
ADCL CX, DX // add high bits with carry
diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s
index e00c727..fc5f28c 100644
--- a/src/pkg/runtime/sys_netbsd_amd64.s
+++ b/src/pkg/runtime/sys_netbsd_amd64.s
@@ -122,31 +122,29 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- LEAQ 8(SP), DI // arg 1 - tp
- MOVQ $0, SI // arg 2 - tzp
- MOVL $418, AX // sys_gettimeofday
+ MOVQ $0, DI // arg 1 - clock_id
+ LEAQ 8(SP), SI // arg 2 - tp
+ MOVL $427, AX // sys_clock_gettime
SYSCALL
MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVL 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
MOVQ AX, sec+0(FP)
- IMULQ $1000, DX
MOVL DX, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),7,$32
- LEAQ 8(SP), DI // arg 1 - tp
- MOVQ $0, SI // arg 2 - tzp
- MOVL $418, AX // sys_gettimeofday
+ MOVQ $0, DI // arg 1 - clock_id
+ LEAQ 8(SP), SI // arg 2 - tp
+ MOVL $427, AX // sys_clock_gettime
SYSCALL
MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVL 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
// return nsec in AX
IMULQ $1000000000, AX
- IMULQ $1000, DX
ADDQ DX, AX
RET
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index f002f8e..f792155 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -98,40 +98,38 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- MOVL $116, AX
+ MOVL $232, AX
LEAL 12(SP), BX
- MOVL BX, 4(SP)
- MOVL $0, 8(SP)
+ MOVL $0, 4(SP)
+ MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // usec
+ MOVL 16(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
MOVL AX, sec+0(FP)
MOVL $0, sec+4(FP)
- IMULL $1000, BX
MOVL BX, nsec+8(FP)
RET
// int64 nanotime(void) so really
// void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB),7,$32
- MOVL $116, AX
+ MOVL $232, AX
LEAL 12(SP), BX
- MOVL BX, 4(SP)
- MOVL $0, 8(SP)
+ MOVL $0, 4(SP)
+ MOVL BX, 8(SP)
INT $0x80
MOVL 12(SP), AX // sec
- MOVL 16(SP), BX // usec
+ MOVL 16(SP), BX // nsec
- // sec is in AX, usec in BX
+ // sec is in AX, nsec in BX
// convert to DX:AX nsec
MOVL $1000000000, CX
MULL CX
- IMULL $1000, BX
ADDL BX, AX
ADCL $0, DX
-
+
MOVL ret+0(FP), DI
MOVL AX, 0(DI)
MOVL DX, 4(DI)
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 6b674a5..e569bec 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -130,31 +130,29 @@
// func now() (sec int64, nsec int32)
TEXT time·now(SB), 7, $32
- LEAQ 8(SP), DI // arg 1 - tp
- MOVQ $0, SI // arg 2 - tzp
- MOVL $116, AX // sys_gettimeofday
+ MOVQ $0, DI // arg 1 - clock_id
+ LEAQ 8(SP), SI // arg 2 - tp
+ MOVL $232, AX // sys_clock_gettime
SYSCALL
- MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVL 8(SP), AX // sec
+ MOVQ 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
MOVQ AX, sec+0(FP)
- IMULQ $1000, DX
MOVL DX, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),7,$32
- LEAQ 8(SP), DI // arg 1 - tp
- MOVQ $0, SI // arg 2 - tzp
- MOVL $116, AX // sys_gettimeofday
+ MOVQ $0, DI // arg 1 - clock_id
+ LEAQ 8(SP), SI // arg 2 - tp
+ MOVL $232, AX // sys_clock_gettime
SYSCALL
- MOVQ 8(SP), AX // sec
- MOVL 16(SP), DX // usec
+ MOVL 8(SP), AX // sec
+ MOVQ 16(SP), DX // nsec
- // sec is in AX, usec in DX
+ // sec is in AX, nsec in DX
// return nsec in AX
IMULQ $1000000000, AX
- IMULQ $1000, DX
ADDQ DX, AX
RET