Closed quentinmit closed 7 years ago
I flipped through the other OSs. A few others use wall-clock time, as well:
clock_gettime(CLOCK_REALTIME)
. If the internet rumors are true, Solaris doesn't have CLOCK_MONOTONIC. We should perhaps use gethrtime
on Solaris.clock_gettime(CLOCK_REALTIME)
. As far as I can tell, CLOCK_MONOTONIC is available and we should use it.At least Solaris version 12 does have CLOCK_MONOTONIC
. It is documented as CLOCK_HIGHRES
, but CLOCK_MONOTONIC
is defined in CLOCK_HIGHRES
and CLOCK_HIGHRES
is defined by the man page to be monotonic.
FYI clock_gettime
was introduced in September 2016 with the release of macOS 10.12 (Sierra)
It will be some time before we can drop support for all pre-10.12 OS X versions, so I'm afraid we can't rely on 10.12-only syscalls now.
@minux, we can use it when available.
But mach_absolute_time is available everywhere. The only problem is that I don't know if its Mach absolute time unit changes dynamically (in the lifetime of a process) or not.
note, AbsoluteToNanosecond is deprecated, but we can use absolutetime_to_nanosecond instead. However, we still need to figure out how to reimplement its functionality in Go. I'm hoping it doesn't require kernel specific memory accesses.
Using mach_timebase_info
you can convert Mach absolute time to nanoseconds:
mach_timebase_info_data_t info;
mach_timebase_info(&info);
uint64_t start = mach_absolute_time();
usleep(2000000);
uint64_t duration = mach_absolute_time() - start;
// Convert to nanoseconds
duration = duration * info.numer / info.denom;
printf("%lld ns\n", (long long) duration);
From developer.apple.com
mach_absolute_time is using rdtsc with some kernel provided magic numbers from comm page.
// from xnu-3248.60.11.1.2~2 _mach_absolute_time: 00007fff5fc25726 pushq %rbp 00007fff5fc25727 movq %rsp, %rbp 00007fff5fc2572a movabsq $0x7fffffe00050, %rsi ## imm = 0x7FFFFFE00050 00007fff5fc25734 movl 0x18(%rsi), %r8d 00007fff5fc25738 testl %r8d, %r8d 00007fff5fc2573b je 0x7fff5fc25734 00007fff5fc2573d lfence 00007fff5fc25740 rdtsc 00007fff5fc25742 lfence 00007fff5fc25745 shlq $0x20, %rdx 00007fff5fc25749 orq %rdx, %rax 00007fff5fc2574c movl 0xc(%rsi), %ecx 00007fff5fc2574f andl $0x1f, %ecx 00007fff5fc25752 subq (%rsi), %rax 00007fff5fc25755 shlq %cl, %rax 00007fff5fc25758 movl 0x8(%rsi), %ecx 00007fff5fc2575b mulq %rcx 00007fff5fc2575e shrdq $0x20, %rdx, %rax 00007fff5fc25763 addq 0x10(%rsi), %rax 00007fff5fc25767 cmpl 0x18(%rsi), %r8d 00007fff5fc2576b jne 0x7fff5fc25734 00007fff5fc2576d popq %rbp 00007fff5fc2576e retq 00007fff5fc2576f nop
I think it's the same as our current runtime.nanotime implementation.
My nanotime replacement to support monototic nanoseconds:
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVQ $0x7fffffe00000, SI // comm page base
timeloop:
MOVL nt_generation(SI), R8
TESTL R8, R8
JZ timeloop
RDTSC
SHLQ $32, DX
ORQ DX, AX
MOVL nt_shift(SI), CX
SUBQ nt_tsc_base(SI), AX
SHLQ CX, AX
MOVL nt_scale(SI), CX
MULQ CX
SHRQ $32, AX:DX
ADDQ nt_ns_base(SI), AX
CMPL nt_generation(SI), R8
JNE timeloop
MOVQ AX, ret+0(FP)
RET
The algorithm is based on xnu's mach_absolute_time and works on Intel Macs.
My intention is to follow Go's contributions guidelines next.
CL https://golang.org/cl/35292 mentions this issue.
runtime.nanotime currently returns wallclock time, which means timers do not function correctly in the presence of NTP. We should use
mach_absolute_time
instead, which returns a monotonic nanoseconds-since-boot timer. (Officially, it returns time in "absolute time units" and you have to multiply by a constant to get nanoseconds. But the implementation of bothmach_absolute_time
andgettimeofday
assume/document that it's really nanoseconds...)This has the bonus of being much simpler than gettimeofday, so it will also reduce our chances of being hit by a change in the kernel ABI.
Targeting 1.9 because this seems too dangerous for 1.8.