Make our time types transparent (#2374)

Motivation:

Our time types are trivial, and they should be fully transparent. This
produces minor performance improvements in code handling time types, but
is mostly useful in terms of allowing the compiler to observe that these
functions have no side effects, thereby eliding some ARC traffic.

Modifications:

Make our time types inlinable.

Result:

Better performance.
This commit is contained in:
Cory Benfield 2023-02-21 13:06:06 +00:00 committed by GitHub
parent 4dfae01cc6
commit 108d4646a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 39 additions and 5 deletions

View File

@ -445,7 +445,8 @@ public struct TimeAmount: Hashable, Sendable {
/// The nanoseconds representation of the `TimeAmount`. /// The nanoseconds representation of the `TimeAmount`.
public let nanoseconds: Int64 public let nanoseconds: Int64
private init(_ nanoseconds: Int64) { /* private but */ @inlinable
init(_ nanoseconds: Int64) {
self.nanoseconds = nanoseconds self.nanoseconds = nanoseconds
} }
@ -454,6 +455,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of nanoseconds this `TimeAmount` represents. /// - amount: the amount of nanoseconds this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func nanoseconds(_ amount: Int64) -> TimeAmount { public static func nanoseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount) return TimeAmount(amount)
} }
@ -463,6 +465,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of microseconds this `TimeAmount` represents. /// - amount: the amount of microseconds this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func microseconds(_ amount: Int64) -> TimeAmount { public static func microseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount * 1000) return TimeAmount(amount * 1000)
} }
@ -472,6 +475,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of milliseconds this `TimeAmount` represents. /// - amount: the amount of milliseconds this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func milliseconds(_ amount: Int64) -> TimeAmount { public static func milliseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount * (1000 * 1000)) return TimeAmount(amount * (1000 * 1000))
} }
@ -481,6 +485,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of seconds this `TimeAmount` represents. /// - amount: the amount of seconds this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func seconds(_ amount: Int64) -> TimeAmount { public static func seconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount * (1000 * 1000 * 1000)) return TimeAmount(amount * (1000 * 1000 * 1000))
} }
@ -490,6 +495,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of minutes this `TimeAmount` represents. /// - amount: the amount of minutes this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func minutes(_ amount: Int64) -> TimeAmount { public static func minutes(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount * (1000 * 1000 * 1000 * 60)) return TimeAmount(amount * (1000 * 1000 * 1000 * 60))
} }
@ -499,12 +505,14 @@ public struct TimeAmount: Hashable, Sendable {
/// - parameters: /// - parameters:
/// - amount: the amount of hours this `TimeAmount` represents. /// - amount: the amount of hours this `TimeAmount` represents.
/// - returns: the `TimeAmount` for the given amount. /// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func hours(_ amount: Int64) -> TimeAmount { public static func hours(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount * (1000 * 1000 * 1000 * 60 * 60)) return TimeAmount(amount * (1000 * 1000 * 1000 * 60 * 60))
} }
} }
extension TimeAmount: Comparable { extension TimeAmount: Comparable {
@inlinable
public static func < (lhs: TimeAmount, rhs: TimeAmount) -> Bool { public static func < (lhs: TimeAmount, rhs: TimeAmount) -> Bool {
return lhs.nanoseconds < rhs.nanoseconds return lhs.nanoseconds < rhs.nanoseconds
} }
@ -512,30 +520,37 @@ extension TimeAmount: Comparable {
extension TimeAmount: AdditiveArithmetic { extension TimeAmount: AdditiveArithmetic {
/// The zero value for `TimeAmount`. /// The zero value for `TimeAmount`.
@inlinable
public static var zero: TimeAmount { public static var zero: TimeAmount {
return TimeAmount.nanoseconds(0) return TimeAmount.nanoseconds(0)
} }
@inlinable
public static func + (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount { public static func + (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(lhs.nanoseconds + rhs.nanoseconds) return TimeAmount(lhs.nanoseconds + rhs.nanoseconds)
} }
@inlinable
public static func +=(lhs: inout TimeAmount, rhs: TimeAmount) { public static func +=(lhs: inout TimeAmount, rhs: TimeAmount) {
lhs = lhs + rhs lhs = lhs + rhs
} }
@inlinable
public static func - (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount { public static func - (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(lhs.nanoseconds - rhs.nanoseconds) return TimeAmount(lhs.nanoseconds - rhs.nanoseconds)
} }
@inlinable
public static func -=(lhs: inout TimeAmount, rhs: TimeAmount) { public static func -=(lhs: inout TimeAmount, rhs: TimeAmount) {
lhs = lhs - rhs lhs = lhs - rhs
} }
@inlinable
public static func * <T: BinaryInteger>(lhs: T, rhs: TimeAmount) -> TimeAmount { public static func * <T: BinaryInteger>(lhs: T, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(Int64(lhs) * rhs.nanoseconds) return TimeAmount(Int64(lhs) * rhs.nanoseconds)
} }
@inlinable
public static func * <T: BinaryInteger>(lhs: TimeAmount, rhs: T) -> TimeAmount { public static func * <T: BinaryInteger>(lhs: TimeAmount, rhs: T) -> TimeAmount {
return TimeAmount(lhs.nanoseconds * Int64(rhs)) return TimeAmount(lhs.nanoseconds * Int64(rhs))
} }
@ -563,13 +578,14 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
public typealias Value = UInt64 public typealias Value = UInt64
// This really should be an UInt63 but we model it as Int64 with >=0 assert // This really should be an UInt63 but we model it as Int64 with >=0 assert
private var _uptimeNanoseconds: Int64 { /* private but */ @usableFromInline var _uptimeNanoseconds: Int64 {
didSet { didSet {
assert(self._uptimeNanoseconds >= 0) assert(self._uptimeNanoseconds >= 0)
} }
} }
/// The nanoseconds since boot representation of the `NIODeadline`. /// The nanoseconds since boot representation of the `NIODeadline`.
@inlinable
public var uptimeNanoseconds: UInt64 { public var uptimeNanoseconds: UInt64 {
return .init(self._uptimeNanoseconds) return .init(self._uptimeNanoseconds)
} }
@ -577,7 +593,7 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
public static let distantPast = NIODeadline(0) public static let distantPast = NIODeadline(0)
public static let distantFuture = NIODeadline(.init(Int64.max)) public static let distantFuture = NIODeadline(.init(Int64.max))
private init(_ nanoseconds: Int64) { /* private but */ @inlinable init(_ nanoseconds: Int64) {
precondition(nanoseconds >= 0) precondition(nanoseconds >= 0)
self._uptimeNanoseconds = nanoseconds self._uptimeNanoseconds = nanoseconds
} }
@ -593,8 +609,8 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
/// we make that call here, directly from NIO. /// we make that call here, directly from NIO.
/// ///
/// - TODO: Investigate optimizing the call to `DispatchTime.now()` away on other platforms too. /// - TODO: Investigate optimizing the call to `DispatchTime.now()` away on other platforms too.
@inline(__always) @inlinable
private static func timeNow() -> UInt64 { static func timeNow() -> UInt64 {
#if os(Linux) #if os(Linux)
var ts = timespec() var ts = timespec()
clock_gettime(CLOCK_MONOTONIC, &ts) clock_gettime(CLOCK_MONOTONIC, &ts)
@ -607,38 +623,55 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
#endif // os(Linux) #endif // os(Linux)
} }
@inlinable
public static func now() -> NIODeadline { public static func now() -> NIODeadline {
return NIODeadline.uptimeNanoseconds(timeNow()) return NIODeadline.uptimeNanoseconds(timeNow())
} }
@inlinable
public static func uptimeNanoseconds(_ nanoseconds: UInt64) -> NIODeadline { public static func uptimeNanoseconds(_ nanoseconds: UInt64) -> NIODeadline {
return NIODeadline(Int64(min(UInt64(Int64.max), nanoseconds))) return NIODeadline(Int64(min(UInt64(Int64.max), nanoseconds)))
} }
@inlinable
public static func == (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds == rhs.uptimeNanoseconds
}
@inlinable
public func hash(into hasher: inout Hasher) {
hasher.combine(self.uptimeNanoseconds)
}
} }
extension NIODeadline: Comparable { extension NIODeadline: Comparable {
@inlinable
public static func < (lhs: NIODeadline, rhs: NIODeadline) -> Bool { public static func < (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds < rhs.uptimeNanoseconds return lhs.uptimeNanoseconds < rhs.uptimeNanoseconds
} }
@inlinable
public static func > (lhs: NIODeadline, rhs: NIODeadline) -> Bool { public static func > (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds > rhs.uptimeNanoseconds return lhs.uptimeNanoseconds > rhs.uptimeNanoseconds
} }
} }
extension NIODeadline: CustomStringConvertible { extension NIODeadline: CustomStringConvertible {
@inlinable
public var description: String { public var description: String {
return self.uptimeNanoseconds.description return self.uptimeNanoseconds.description
} }
} }
extension NIODeadline { extension NIODeadline {
@inlinable
public static func - (lhs: NIODeadline, rhs: NIODeadline) -> TimeAmount { public static func - (lhs: NIODeadline, rhs: NIODeadline) -> TimeAmount {
// This won't ever crash, NIODeadlines are guaranteed to be within 0 ..< 2^63-1 nanoseconds so the result can // This won't ever crash, NIODeadlines are guaranteed to be within 0 ..< 2^63-1 nanoseconds so the result can
// definitely be stored in a TimeAmount (which is an Int64). // definitely be stored in a TimeAmount (which is an Int64).
return .nanoseconds(Int64(lhs.uptimeNanoseconds) - Int64(rhs.uptimeNanoseconds)) return .nanoseconds(Int64(lhs.uptimeNanoseconds) - Int64(rhs.uptimeNanoseconds))
} }
@inlinable
public static func + (lhs: NIODeadline, rhs: TimeAmount) -> NIODeadline { public static func + (lhs: NIODeadline, rhs: TimeAmount) -> NIODeadline {
let partial: Int64 let partial: Int64
let overflow: Bool let overflow: Bool
@ -653,6 +686,7 @@ extension NIODeadline {
return NIODeadline(partial) return NIODeadline(partial)
} }
@inlinable
public static func - (lhs: NIODeadline, rhs: TimeAmount) -> NIODeadline { public static func - (lhs: NIODeadline, rhs: TimeAmount) -> NIODeadline {
if rhs.nanoseconds < 0 { if rhs.nanoseconds < 0 {
// The addition won't crash because the worst that could happen is `UInt64(Int64.max) + UInt64(Int64.max)` // The addition won't crash because the worst that could happen is `UInt64(Int64.max) + UInt64(Int64.max)`