From: Keith Randall Date: Tue, 1 May 2018 16:42:04 +0000 (-0700) Subject: runtime: use libc for nanotime on Darwin X-Git-Tag: go1.11beta1~391 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=cc09212f59ee215cae5345dc1ffcd1ed81664e1b;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 54d5eaa014..5ca26a2d5f 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -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) diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go index bedaf99961..e3a25c5312 100644 --- a/src/runtime/defs_darwin.go +++ b/src/runtime/defs_darwin.go @@ -17,6 +17,7 @@ package runtime #define __DARWIN_UNIX03 0 #include #include +#include #include #include #include @@ -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 diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go index 51c6340dfa..7f8ae9c934 100644 --- a/src/runtime/defs_darwin_386.go +++ b/src/runtime/defs_darwin_386.go @@ -395,3 +395,7 @@ type pthreadattr struct { X__sig int32 X__opaque [36]int8 } +type machTimebaseInfo struct { + numer uint32 + denom uint32 +} diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go index d1483e7db5..f35b90a5fa 100644 --- a/src/runtime/defs_darwin_amd64.go +++ b/src/runtime/defs_darwin_amd64.go @@ -398,3 +398,7 @@ type pthreadattr struct { X__sig int64 X__opaque [56]int8 } +type machTimebaseInfo struct { + numer uint32 + denom uint32 +} diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go index 7570dcaeb2..5c0786e411 100644 --- a/src/runtime/stubs3.go +++ b/src/runtime/stubs3.go @@ -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 index 0000000000..ad0e48e455 --- /dev/null +++ b/src/runtime/stubs4.go @@ -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 diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index 8757486e22..3bdd1f2b16 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -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" diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index 16ca3e06ae..44a686f400 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -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 diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index e48145a450..24db7f52cd 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -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