Commit cc09212f authored by Keith Randall's avatar Keith Randall

runtime: use libc for nanotime on Darwin

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: default avatarIan Lance Taylor <iant@golang.org>
parent e86c2678
...@@ -704,6 +704,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12 ...@@ -704,6 +704,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
MOVL g(CX), DI MOVL g(CX), DI
CMPL SI, DI CMPL SI, DI
JEQ noswitch JEQ noswitch
CMPL DI, m_gsignal(BP)
JEQ noswitch
CALL gosave<>(SB) CALL gosave<>(SB)
get_tls(CX) get_tls(CX)
MOVL SI, g(CX) MOVL SI, g(CX)
......
...@@ -17,6 +17,7 @@ package runtime ...@@ -17,6 +17,7 @@ package runtime
#define __DARWIN_UNIX03 0 #define __DARWIN_UNIX03 0
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/message.h> #include <mach/message.h>
#include <mach/mach_time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <errno.h> #include <errno.h>
...@@ -184,3 +185,5 @@ type Kevent C.struct_kevent ...@@ -184,3 +185,5 @@ type Kevent C.struct_kevent
type Pthread C.pthread_t type Pthread C.pthread_t
type PthreadAttr C.pthread_attr_t type PthreadAttr C.pthread_attr_t
type MachTimebaseInfo C.mach_timebase_info_data_t
...@@ -395,3 +395,7 @@ type pthreadattr struct { ...@@ -395,3 +395,7 @@ type pthreadattr struct {
X__sig int32 X__sig int32
X__opaque [36]int8 X__opaque [36]int8
} }
type machTimebaseInfo struct {
numer uint32
denom uint32
}
...@@ -398,3 +398,7 @@ type pthreadattr struct { ...@@ -398,3 +398,7 @@ type pthreadattr struct {
X__sig int64 X__sig int64
X__opaque [56]int8 X__opaque [56]int8
} }
type machTimebaseInfo struct {
numer uint32
denom uint32
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// +build !windows // +build !windows
// +build !nacl // +build !nacl
// +build !freebsd // +build !freebsd
// +build !darwin
package runtime package runtime
......
// 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
...@@ -124,6 +124,28 @@ func open(name *byte, mode, perm int32) (ret int32) { ...@@ -124,6 +124,28 @@ func open(name *byte, mode, perm int32) (ret int32) {
} }
func open_trampoline() 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. // Not used on Darwin, but must be defined.
func exitThread(wait *uint32) { func exitThread(wait *uint32) {
} }
...@@ -150,6 +172,9 @@ 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_error __error "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_usleep usleep "/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. // Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210 // TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
//go:cgo_import_dynamic _ _ "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic _ _ "/usr/lib/libSystem.B.dylib"
...@@ -311,13 +311,37 @@ TEXT time·now(SB),NOSPLIT,$0-20 ...@@ -311,13 +311,37 @@ TEXT time·now(SB),NOSPLIT,$0-20
MOVL DX, nsec+8(FP) MOVL DX, nsec+8(FP)
RET RET
// func nanotime() int64 GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
TEXT runtime·nanotime(SB),NOSPLIT,$0
CALL runtime·now(SB) TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
SUBL runtime·startNano(SB), AX PUSHL BP
SBBL runtime·startNano+4(SB), DX MOVL SP, BP
MOVL AX, ret_lo+0(FP) SUBL $8+(machTimebaseInfo__size+15)/16*16, SP
MOVL DX, ret_hi+4(FP) 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 RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
......
...@@ -110,33 +110,35 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 ...@@ -110,33 +110,35 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
#define v17_gtod_scale 0xe8 #define v17_gtod_scale 0xe8
#define v17_gtod_tkspersec 0xf0 #define v17_gtod_tkspersec 0xf0
TEXT runtime·nanotime(SB),NOSPLIT,$0-8 GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
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
// Gathered all the data we need. Compute monotonic time: TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
// ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base PUSHQ BP
// The multiply and shift extracts the top 64 bits of the 96-bit product. MOVQ SP, BP
SHLQ $32, DX MOVQ DI, BX
ADDQ DX, AX CALL libc_mach_absolute_time(SB)
SUBQ R10, AX MOVQ AX, 0(BX)
MULQ R11 MOVL timebase<>+machTimebaseInfo_numer(SB), SI
SHRQ $32, AX:DX MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
ADDQ R12, AX TESTL DI, DI
MOVQ runtime·startNano(SB), CX JNE initialized
SUBQ CX, AX
MOVQ AX, ret+0(FP) 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 RET
TEXT time·now(SB), NOSPLIT, $32-24 TEXT time·now(SB), NOSPLIT, $32-24
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment