wip: Use clock_gettime for NIODeadline.now() (#2119)

* wip: Use clock_gettime for NIODeadline.now()

Signed-off-by: Si Beaumont <beaumont@apple.com>

* fixup: Add #if os(Linux) for clock_gettime use

* fixup: Add doc comments

Signed-off-by: Si Beaumont <beaumont@apple.com>
This commit is contained in:
Si Beaumont 2022-05-19 09:28:31 +01:00 committed by GitHub
parent 9294f8da3b
commit 92d20d92b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 1 deletions

View File

@ -26,6 +26,7 @@ void CNIOLinux_i_do_nothing_just_working_around_a_darwin_toolchain_bug(void) {}
#include <sys/prctl.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
_Static_assert(sizeof(CNIOLinux_mmsghdr) == sizeof(struct mmsghdr),
"sizes of CNIOLinux_mmsghdr and struct mmsghdr differ");

View File

@ -14,6 +14,9 @@
import NIOConcurrencyHelpers
import Dispatch
#if os(Linux)
import CNIOLinux
#endif // os(Linux)
/// Returned once a task was scheduled on the `EventLoop` for later execution.
///
@ -478,8 +481,33 @@ public struct NIODeadline: Equatable, Hashable, NIOSendable {
self._uptimeNanoseconds = nanoseconds
}
/// Getting the time is a very common operation so it warrants optimization.
///
/// Prior to this function, NIO relied on `DispatchTime.now()`, on all platforms. In addition to
/// the overhead of making a library call, the underlying implementation has a lot of branches
/// because `libdispatch` supports many more usecases than we are making use of here.
///
/// On Linux, `DispachTime.now()` _always_ results in a simple call to `clock_gettime(3)` and so
/// we make that call here, directly from NIO.
///
/// - TODO: Investigate optimizing the call to `DispatchTime.now()` away on other platforms too.
@inline(__always)
private static func timeNow() -> UInt64 {
#if os(Linux)
var ts = timespec()
clock_gettime(CLOCK_MONOTONIC, &ts)
/// We use unsafe arithmetic here because `UInt64.max` nanoseconds is more than 580 years,
/// and the odds that this code will still be running 530 years from now is very, very low,
/// so as a practical matter this will never overflow.
return UInt64(ts.tv_sec) &* 1_000_000_000 &+ UInt64(ts.tv_nsec)
#else // os(Linux)
return DispatchTime.now().uptimeNanoseconds
#endif // os(Linux)
}
public static func now() -> NIODeadline {
return NIODeadline.uptimeNanoseconds(DispatchTime.now().uptimeNanoseconds)
return NIODeadline.uptimeNanoseconds(timeNow())
}
public static func uptimeNanoseconds(_ nanoseconds: UInt64) -> NIODeadline {