Skip to content

Commit cc09212

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent e86c267 commit cc09212

9 files changed

+107
-33
lines changed

src/runtime/asm_386.s

+2
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
704704
MOVL g(CX), DI
705705
CMPL SI, DI
706706
JEQ noswitch
707+
CMPL DI, m_gsignal(BP)
708+
JEQ noswitch
707709
CALL gosave<>(SB)
708710
get_tls(CX)
709711
MOVL SI, g(CX)

src/runtime/defs_darwin.go

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package runtime
1717
#define __DARWIN_UNIX03 0
1818
#include <mach/mach.h>
1919
#include <mach/message.h>
20+
#include <mach/mach_time.h>
2021
#include <sys/types.h>
2122
#include <sys/time.h>
2223
#include <errno.h>
@@ -184,3 +185,5 @@ type Kevent C.struct_kevent
184185

185186
type Pthread C.pthread_t
186187
type PthreadAttr C.pthread_attr_t
188+
189+
type MachTimebaseInfo C.mach_timebase_info_data_t

src/runtime/defs_darwin_386.go

+4
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,7 @@ type pthreadattr struct {
395395
X__sig int32
396396
X__opaque [36]int8
397397
}
398+
type machTimebaseInfo struct {
399+
numer uint32
400+
denom uint32
401+
}

src/runtime/defs_darwin_amd64.go

+4
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,7 @@ type pthreadattr struct {
398398
X__sig int64
399399
X__opaque [56]int8
400400
}
401+
type machTimebaseInfo struct {
402+
numer uint32
403+
denom uint32
404+
}

src/runtime/stubs3.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// +build !windows
88
// +build !nacl
99
// +build !freebsd
10+
// +build !darwin
1011

1112
package runtime
1213

src/runtime/stubs4.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build darwin,arm darwin,arm64
6+
7+
package runtime
8+
9+
func nanotime() int64

src/runtime/sys_darwin.go

+25
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,28 @@ func open(name *byte, mode, perm int32) (ret int32) {
124124
}
125125
func open_trampoline()
126126

127+
//go:nosplit
128+
//go:cgo_unsafe_args
129+
func nanotime() int64 {
130+
var r struct {
131+
t int64 // raw timer
132+
numer, denom uint32 // conversion factors. nanoseconds = t * numer / denom.
133+
}
134+
asmcgocall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r))
135+
// Note: Apple seems unconcerned about overflow here. See
136+
// https://developer.apple.com/library/content/qa/qa1398/_index.html
137+
// Note also, numer == denom == 1 is common.
138+
t := r.t
139+
if r.numer != 1 {
140+
t *= int64(r.numer)
141+
}
142+
if r.denom != 1 {
143+
t /= int64(r.denom)
144+
}
145+
return t
146+
}
147+
func nanotime_trampoline()
148+
127149
// Not used on Darwin, but must be defined.
128150
func exitThread(wait *uint32) {
129151
}
@@ -150,6 +172,9 @@ func exitThread(wait *uint32) {
150172
//go:cgo_import_dynamic libc_error __error "/usr/lib/libSystem.B.dylib"
151173
//go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib"
152174

175+
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
176+
//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
177+
153178
// Magic incantation to get libSystem actually dynamically linked.
154179
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
155180
//go:cgo_import_dynamic _ _ "/usr/lib/libSystem.B.dylib"

src/runtime/sys_darwin_386.s

+31-7
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,37 @@ TEXT time·now(SB),NOSPLIT,$0-20
311311
MOVL DX, nsec+8(FP)
312312
RET
313313

314-
// func nanotime() int64
315-
TEXT runtime·nanotime(SB),NOSPLIT,$0
316-
CALL runtime·now(SB)
317-
SUBL runtime·startNano(SB), AX
318-
SBBL runtime·startNano+4(SB), DX
319-
MOVL AX, ret_lo+0(FP)
320-
MOVL DX, ret_hi+4(FP)
314+
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
315+
316+
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
317+
PUSHL BP
318+
MOVL SP, BP
319+
SUBL $8+(machTimebaseInfo__size+15)/16*16, SP
320+
CALL libc_mach_absolute_time(SB)
321+
MOVL 16+(machTimebaseInfo__size+15)/16*16(SP), CX
322+
MOVL AX, 0(CX)
323+
MOVL DX, 4(CX)
324+
MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
325+
MOVL timebase<>+machTimebaseInfo_numer(SB), SI
326+
TESTL DI, DI
327+
JNE initialized
328+
329+
LEAL 4(SP), AX
330+
MOVL AX, 0(SP)
331+
CALL libc_mach_timebase_info(SB)
332+
MOVL 4+machTimebaseInfo_numer(SP), SI
333+
MOVL 4+machTimebaseInfo_denom(SP), DI
334+
335+
MOVL SI, timebase<>+machTimebaseInfo_numer(SB)
336+
MOVL DI, AX
337+
XCHGL AX, timebase<>+machTimebaseInfo_denom(SB) // atomic write
338+
MOVL 16+(machTimebaseInfo__size+15)/16*16(SP), CX
339+
340+
initialized:
341+
MOVL SI, 8(CX)
342+
MOVL DI, 12(CX)
343+
MOVL BP, SP
344+
POPL BP
321345
RET
322346

323347
TEXT runtime·sigprocmask(SB),NOSPLIT,$0

src/runtime/sys_darwin_amd64.s

+28-26
Original file line numberDiff line numberDiff line change
@@ -110,33 +110,35 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
110110
#define v17_gtod_scale 0xe8
111111
#define v17_gtod_tkspersec 0xf0
112112

113-
TEXT runtime·nanotime(SB),NOSPLIT,$0-8
114-
MOVQ $0x7fffffe00000, BP /* comm page base */
115-
// Loop trying to take a consistent snapshot
116-
// of the time parameters.
117-
timeloop:
118-
MOVL nt_generation(BP), R9
119-
TESTL R9, R9
120-
JZ timeloop
121-
RDTSC
122-
MOVQ nt_tsc_base(BP), R10
123-
MOVL nt_scale(BP), R11
124-
MOVQ nt_ns_base(BP), R12
125-
CMPL nt_generation(BP), R9
126-
JNE timeloop
113+
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
127114

128-
// Gathered all the data we need. Compute monotonic time:
129-
// ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base
130-
// The multiply and shift extracts the top 64 bits of the 96-bit product.
131-
SHLQ $32, DX
132-
ADDQ DX, AX
133-
SUBQ R10, AX
134-
MULQ R11
135-
SHRQ $32, AX:DX
136-
ADDQ R12, AX
137-
MOVQ runtime·startNano(SB), CX
138-
SUBQ CX, AX
139-
MOVQ AX, ret+0(FP)
115+
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
116+
PUSHQ BP
117+
MOVQ SP, BP
118+
MOVQ DI, BX
119+
CALL libc_mach_absolute_time(SB)
120+
MOVQ AX, 0(BX)
121+
MOVL timebase<>+machTimebaseInfo_numer(SB), SI
122+
MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read
123+
TESTL DI, DI
124+
JNE initialized
125+
126+
SUBQ $(machTimebaseInfo__size+15)/16*16, SP
127+
MOVQ SP, DI
128+
CALL libc_mach_timebase_info(SB)
129+
MOVL machTimebaseInfo_numer(SP), SI
130+
MOVL machTimebaseInfo_denom(SP), DI
131+
ADDQ $(machTimebaseInfo__size+15)/16*16, SP
132+
133+
MOVL SI, timebase<>+machTimebaseInfo_numer(SB)
134+
MOVL DI, AX
135+
XCHGL AX, timebase<>+machTimebaseInfo_denom(SB) // atomic write
136+
137+
initialized:
138+
MOVL SI, 8(BX)
139+
MOVL DI, 12(BX)
140+
MOVQ BP, SP
141+
POPQ BP
140142
RET
141143

142144
TEXT time·now(SB), NOSPLIT, $32-24

0 commit comments

Comments
 (0)