Is there any performance difference between that and mach_absolute_time() ?
Is there any performance difference between that and mach_absolute_time() ?
macOS also has clock constants for a monotonic clock that increases while sleeping (unlike CLOCK_UPTIME_RAW and mach_absolute_time).
_mach_absolute_time:
00000000000012ec pushq %rbp
00000000000012ed movq %rsp, %rbp
00000000000012f0 movabsq $0x7fffffe00050, %rsi ## imm = 0x7FFFFFE00050
00000000000012fa movl 0x18(%rsi), %r8d
00000000000012fe testl %r8d, %r8d
0000000000001301 je 0x12fa
0000000000001303 lfence
0000000000001306 rdtsc
0000000000001308 lfence
000000000000130b shlq $0x20, %rdx
000000000000130f orq %rdx, %rax
0000000000001312 movl 0xc(%rsi), %ecx
0000000000001315 andl $0x1f, %ecx
0000000000001318 subq (%rsi), %rax
000000000000131b shlq %cl, %rax
000000000000131e movl 0x8(%rsi), %ecx
0000000000001321 mulq %rcx
0000000000001324 shrdq $0x20, %rdx, %rax
0000000000001329 addq 0x10(%rsi), %rax
000000000000132d cmpl 0x18(%rsi), %r8d
0000000000001331 jne 0x12fa
0000000000001333 popq %rbp
0000000000001334 retqAFAIR on x86 a locked rdtsc is ~20 cycles. So to answer the gp question, it has around a precision in the few nanoseconds range. Accuracy is a different question, IE compare numbers from the same die, but be a little more suspicious across dies.
No clue how this is implemented on the M1, or if the M1 has the same modern tsc guarantees that x86 has grown over the last few generations of chips.
Sufficiently old versions of mach_absolute_time used a function called clock_get_time() on i386 (if the COMM_PAGE_VERSION was not 1). This changed in macOS 10.5 to a tiny bit of assembly that just read from _COMM_PAGE_NANOTIME on i386/x86_64/ppc (the arm implementation(!!) triggers a software interrupt). The i386/x86_64/ppc definitions were also copied into xnu.
For the next few years it kind of bounced back and forth between libc and xnu, and the routine was complicated by adding timebase conversion as needed. And at some point arm support was added back (it vanished when it first went to xnu), but this time using the commpage if possible.
As for M1, I assume it's using the arm64 routine in xnu, which can be found at https://opensource.apple.com/source/xnu/xnu-7195.50.7.100.1/....
As for clock_gettime_nsec_np(), at least as of Big Sur, it's in libc¹ instead of xnu and defers to mach_continuous_time()/mach_continuous_approximate_time()/mach_absolute_time()/mach_approximate_time() for the CLOCK__RAW[_] clocks. And clock_gettime() for those clocks is implemented in terms of clock_gettime_nsec_np().
¹https://opensource.apple.com/source/Libc/Libc-1439.40.11/gen...
¹Technically it uses mach_continuous_time() first if available (which appears to be equivalent to CLOCK_MONOTONIC_RAW), then clock_gettime(CLOCK_BOOTTIME, &ts) on Linux, then clock_gettime(CLOCK_MONOTONIC, &ts), then some other API for Windows.
²Conveniently enough the value that is equivalent to DISPATCH_TIME_NOW using the monotonic clock is just INT64_MIN, at least in the current encoding.
³Swift makes assumptions about the internal format of dispatch_time_t so I don't know if it actually can meaningfully change. Newer versions of Swift now use stdlib on the system, but any app built with a sufficiently old version of Swift still embeds its own copy of the stdlib. Granted, additions (like the monotonic clock) should be fine, as the Swift API does not actually bridge from dispatch_time_t so it only ends up representing times it has APIs to construct. Since it doesn't have APIs to construct monotonic times, they won't break it.
Specifically if I recall correctly the internal representation of time only allowed for 2 formats (wallclock vs monotonic). I suspect adding other types of clocks could pose back/forward compat challenges. However, this is a wild shot in the dark & I didn't really look into the internals of libdispatch. Maybe ask on their github page?
Generally upgrading a private API to public is a lot of work & goes through a lot of review (having monitored that mailing list & added 1 API during my time there). So if there's a private API probably some team at Apple needed it to deliver a feature but the maintainers were not confident the specific solution they chose generalized well & either requires some work or something else.