]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use libc for nanotime on Darwin
authorKeith Randall <khr@golang.org>
Tue, 1 May 2018 16:42:04 +0000 (09:42 -0700)
committerKeith Randall <khr@golang.org>
Sun, 20 May 2018 00:09:28 +0000 (00:09 +0000)
Use mach_absolute_time and mach_timebase_info to get nanosecond-level
timing information from libc on Darwin.

The conversion code from Apple's arbitrary time unit to nanoseconds is
really annoying.  It would be nice if we could replace the internal
runtime "time" with arbitrary units and put the conversion to nanoseconds
only in the places that really need it (so it isn't in every nanotime call).

It's especially annoying because numer==denom==1 for all the machines
I tried.  Makes it hard to test the conversion code :(

Update #17490

Change-Id: I6c5d602a802f5c24e35184e33d5e8194aa7afa86
Reviewed-on: https://go-review.googlesource.com/110655
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/asm_386.s
src/runtime/defs_darwin.go
src/runtime/defs_darwin_386.go
src/runtime/defs_darwin_amd64.go
src/runtime/stubs3.go
src/runtime/stubs4.go [new file with mode: 0644]
src/runtime/sys_darwin.go
src/runtime/sys_darwin_386.s
src/runtime/sys_darwin_amd64.s

index 54d5eaa014f13a8cf96995234e51c4cd00b6dd5f..5ca26a2d5ffbb4d980c1d45a0d5bb74525218a84 100644 (file)
@@ -704,6 +704,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
        MOVL    g(CX), DI
        CMPL    SI, DI
        JEQ     noswitch
+       CMPL    DI, m_gsignal(BP)
+       JEQ     noswitch
        CALL    gosave<>(SB)
        get_tls(CX)
        MOVL    SI, g(CX)
index bedaf99961f9aae2db5f68493441bb238fb9deef..e3a25c531289cee654ab7f42eb035d643cc62acb 100644 (file)
@@ -17,6 +17,7 @@ package runtime
 #define __DARWIN_UNIX03 0
 #include <mach/mach.h>
 #include <mach/message.h>
+#include <mach/mach_time.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <errno.h>
@@ -184,3 +185,5 @@ type Kevent C.struct_kevent
 
 type Pthread C.pthread_t
 type PthreadAttr C.pthread_attr_t
+
+type MachTimebaseInfo C.mach_timebase_info_data_t
index 51c6340dfa889b28f0ae9101e595559a3f2a8549..7f8ae9c93407b5fb9dee93ef0a226372c44db93e 100644 (file)
@@ -395,3 +395,7 @@ type pthreadattr struct {
        X__sig    int32
        X__opaque [36]int8
 }
+type machTimebaseInfo struct {
+       numer uint32
+       denom uint32
+}
index d1483e7db5fae5ae763c36144883bdf032c20169..f35b90a5face363ce68ace2d10f8f9f46acba6ee 100644 (file)
@@ -398,3 +398,7 @@ type pthreadattr struct {
        X__sig    int64
        X__opaque [56]int8
 }
+type machTimebaseInfo struct {
+       numer uint32
+       denom uint32
+}
index 7570dcaeb2c0472f74400da8582703b6f85e5047..5c0786e411a24ba9dd7777fedd4b4ea43d073758 100644 (file)
@@ -7,6 +7,7 @@
 // +build !windows
 // +build !nacl
 // +build !freebsd
+// +build !darwin
 
 package runtime
 
diff --git a/src/runtime/stubs4.go b/src/runtime/stubs4.go
new file mode 100644 (file)
index 0000000..ad0e48e
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2018 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 darwin,arm darwin,arm64
+
+package runtime
+
+func nanotime() int64
index 8757486e220a8b245e0e828bb04b96bd575cbf96..3bdd1f2b16cb2631d0bda58ef35f7d0abc34df32 100644 (file)
@@ -124,6 +124,28 @@ func open(name *byte, mode, perm int32) (ret int32) {
 }
 func open_trampoline()
 
+//go:nosplit
+//go:cgo_unsafe_args
+func nanotime() int64 {
+       var r struct {
+               t            int64  // raw timer
+               numer, denom uint32 // conversion factors. nanoseconds = t * numer / denom.
+       }
+       asmcgocall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r))
+       // Note: Apple seems unconcerned about overflow here. See
+       // https://developer.apple.com/library/content/qa/qa1398/_index.html
+       // Note also, numer == denom == 1 is common.
+       t := r.t
+       if r.numer != 1 {
+               t *= int64(r.numer)
+       }
+       if r.denom != 1 {
+               t /= int64(r.denom)
+       }
+       return t
+}
+func nanotime_trampoline()
+
 // Not used on Darwin, but must be defined.
 func exitThread(wait *uint32) {
 }
@@ -150,6 +172,9 @@ func exitThread(wait *uint32) {
 //go:cgo_import_dynamic libc_error __error "/usr/lib/libSystem.B.dylib"
 //go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"
 
+//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
+
 // Magic incantation to get libSystem actually dynamically linked.
 // TODO: Why does the code require this?  See cmd/compile/internal/ld/go.go:210
 //go:cgo_import_dynamic _ _ "/usr/lib/libSystem.B.dylib"
index 16ca3e06ae825db83b3c78b02bd26e924c37ce93..44a686f40094da44be0902aebdc728f53d951c62 100644 (file)
@@ -311,13 +311,37 @@ TEXT time·now(SB),NOSPLIT,$0-20
        MOVL    DX, nsec+8(FP)
        RET
 
-// func nanotime() int64
-TEXT runtime·nanotime(SB),NOSPLIT,$0
-       CALL    runtime·now(SB)
-       SUBL    runtime·startNano(SB), AX
-       SBBL    runtime·startNano+4(SB), DX
-       MOVL    AX, ret_lo+0(FP)
-       MOVL    DX, ret_hi+4(FP)
+GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
+
+TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
+       PUSHL   BP
+       MOVL    SP, BP
+       SUBL    $8+(machTimebaseInfo__size+15)/16*16, SP
+       CALL    libc_mach_absolute_time(SB)
+       MOVL    16+(machTimebaseInfo__size+15)/16*16(SP), CX
+       MOVL    AX, 0(CX)
+       MOVL    DX, 4(CX)
+       MOVL    timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
+       MOVL    timebase<>+machTimebaseInfo_numer(SB), SI
+       TESTL   DI, DI
+       JNE     initialized
+
+       LEAL    4(SP), AX
+       MOVL    AX, 0(SP)
+       CALL    libc_mach_timebase_info(SB)
+       MOVL    4+machTimebaseInfo_numer(SP), SI
+       MOVL    4+machTimebaseInfo_denom(SP), DI
+
+       MOVL    SI, timebase<>+machTimebaseInfo_numer(SB)
+       MOVL    DI, AX
+       XCHGL   AX, timebase<>+machTimebaseInfo_denom(SB) // atomic write
+       MOVL    16+(machTimebaseInfo__size+15)/16*16(SP), CX
+
+initialized:
+       MOVL    SI, 8(CX)
+       MOVL    DI, 12(CX)
+       MOVL    BP, SP
+       POPL    BP
        RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
index e48145a45090ff5e024a324c95052481eddbf735..24db7f52cd69875ddd5fddfe46ee92b019cf3483 100644 (file)
@@ -110,33 +110,35 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
 #define        v17_gtod_scale          0xe8
 #define        v17_gtod_tkspersec      0xf0
 
-TEXT runtime·nanotime(SB),NOSPLIT,$0-8
-       MOVQ    $0x7fffffe00000, BP     /* comm page base */
-       // Loop trying to take a consistent snapshot
-       // of the time parameters.
-timeloop:
-       MOVL    nt_generation(BP), R9
-       TESTL   R9, R9
-       JZ      timeloop
-       RDTSC
-       MOVQ    nt_tsc_base(BP), R10
-       MOVL    nt_scale(BP), R11
-       MOVQ    nt_ns_base(BP), R12
-       CMPL    nt_generation(BP), R9
-       JNE     timeloop
+GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
 
-       // Gathered all the data we need. Compute monotonic time:
-       //      ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base
-       // The multiply and shift extracts the top 64 bits of the 96-bit product.
-       SHLQ    $32, DX
-       ADDQ    DX, AX
-       SUBQ    R10, AX
-       MULQ    R11
-       SHRQ    $32, AX:DX
-       ADDQ    R12, AX
-       MOVQ    runtime·startNano(SB), CX
-       SUBQ    CX, AX
-       MOVQ    AX, ret+0(FP)
+TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
+       PUSHQ   BP
+       MOVQ    SP, BP
+       MOVQ    DI, BX
+       CALL    libc_mach_absolute_time(SB)
+       MOVQ    AX, 0(BX)
+       MOVL    timebase<>+machTimebaseInfo_numer(SB), SI
+       MOVL    timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
+       TESTL   DI, DI
+       JNE     initialized
+
+       SUBQ    $(machTimebaseInfo__size+15)/16*16, SP
+       MOVQ    SP, DI
+       CALL    libc_mach_timebase_info(SB)
+       MOVL    machTimebaseInfo_numer(SP), SI
+       MOVL    machTimebaseInfo_denom(SP), DI
+       ADDQ    $(machTimebaseInfo__size+15)/16*16, SP
+
+       MOVL    SI, timebase<>+machTimebaseInfo_numer(SB)
+       MOVL    DI, AX
+       XCHGL   AX, timebase<>+machTimebaseInfo_denom(SB) // atomic write
+
+initialized:
+       MOVL    SI, 8(BX)
+       MOVL    DI, 12(BX)
+       MOVQ    BP, SP
+       POPQ    BP
        RET
 
 TEXT time·now(SB), NOSPLIT, $32-24