forked from ordo-one/package-datetime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import DateTime | ||
|
||
import BenchmarkSupport | ||
@main extension BenchmarkRunner {} | ||
|
||
@_dynamicReplacement(for: registerBenchmarks) | ||
func benchmarks() { | ||
|
||
Benchmark.defaultDesiredDuration = .seconds(2) | ||
Benchmark.defaultDesiredIterations = 1_000 | ||
Benchmark.defaultThroughputScalingFactor = .kilo | ||
|
||
Benchmark("InternalUTCClock.now") { benchmark in | ||
for _ in 0 ..< benchmark.throughputScalingFactor.rawValue { | ||
BenchmarkSupport.blackHole(InternalUTCClock.now) | ||
} | ||
} | ||
|
||
Benchmark("Foundation.Date") { benchmark in | ||
for _ in 0 ..< benchmark.throughputScalingFactor.rawValue { | ||
BenchmarkSupport.blackHole(Foundation.Date()) | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
{ | ||
"pins" : [ | ||
{ | ||
"identity" : "package-benchmark", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ordo-one/package-benchmark", | ||
"state" : { | ||
"revision" : "13d1a5fc228f5553acb22cdbb7f7c217e4b8c51e", | ||
"version" : "0.4.3" | ||
} | ||
}, | ||
{ | ||
"identity" : "package-jemalloc", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ordo-one/package-jemalloc", | ||
"state" : { | ||
"revision" : "e8a5db026963f5bfeac842d9d3f2cc8cde323b49", | ||
"version" : "1.0.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-argument-parser", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-argument-parser", | ||
"state" : { | ||
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", | ||
"version" : "1.2.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-extras-json", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/swift-extras/swift-extras-json", | ||
"state" : { | ||
"revision" : "122b9454ef01bf89a4c190b8fd3717ddd0a2fbd0", | ||
"version" : "0.6.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-numerics", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-numerics", | ||
"state" : { | ||
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", | ||
"version" : "1.0.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-system", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/apple/swift-system", | ||
"state" : { | ||
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", | ||
"version" : "1.2.1" | ||
} | ||
}, | ||
{ | ||
"identity" : "texttable", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/ordo-one/TextTable", | ||
"state" : { | ||
"revision" : "a27a07300cf4ae322e0079ca0a475c5583dd575f", | ||
"version" : "0.0.2" | ||
} | ||
} | ||
], | ||
"version" : 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// swift-tools-version: 5.7 | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "package-datetime", | ||
platforms: [ | ||
.macOS(.v13) | ||
], | ||
products: [ | ||
.library( | ||
name: "DateTime", | ||
targets: ["DateTime"] | ||
) | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "0.4.2")) | ||
], | ||
targets: [ | ||
.target( | ||
name: "DateTime", | ||
dependencies: [] | ||
), | ||
.testTarget( | ||
name: "DateTimeTests", | ||
dependencies: ["DateTime"] | ||
), | ||
|
||
// Benchmark targets | ||
.executableTarget( | ||
name: "Clocks", | ||
dependencies: [ | ||
.product(name: "BenchmarkSupport", package: "package-benchmark"), | ||
"DateTime" | ||
], | ||
path: "Benchmarks/Clocks" | ||
) | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// This file contains the specific Foundation constructs we allow to use internally | ||
|
||
@_exported import struct Foundation.Calendar | ||
@_exported import struct Foundation.Date | ||
@_exported import struct Foundation.TimeZone |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// An implementation of an UTC clock using Ordo:s internal datetime representation | ||
|
||
// swiftlint:disable line_length identifier_name | ||
|
||
// Largely adopted by Swift's ContinuousClock | ||
// https://github.com/apple/swift/blob/48987de3d3ab228eed4867949795c188759df234/stdlib/public/Concurrency/ContinuousClock.swift#L49 | ||
|
||
#if canImport(Darwin) | ||
import Darwin | ||
#elseif canImport(Glibc) | ||
import Glibc | ||
#else | ||
#error("Unsupported Platform") | ||
#endif | ||
|
||
public struct InternalUTCClock { | ||
/// A continuous point in time used for `InternalUTCClock`. | ||
public struct Instant: Codable, Sendable { | ||
internal var _value: Swift.Duration | ||
|
||
internal init(_value: Swift.Duration) { | ||
self._value = _value | ||
} | ||
} | ||
|
||
public init() {} | ||
} | ||
|
||
public extension Clock where Self == InternalUTCClock { | ||
/// A clock that measures time that always increments but does not stop | ||
/// incrementing while the system is asleep. | ||
/// | ||
/// try await Task.sleep(until: .now + .seconds(3), clock: .continuous) | ||
/// | ||
static var internalUTC: InternalUTCClock { return InternalUTCClock() } | ||
} | ||
|
||
extension InternalUTCClock: Clock { | ||
/// The current continuous instant. | ||
public var now: InternalUTCClock.Instant { | ||
InternalUTCClock.now | ||
} | ||
|
||
/// The minimum non-zero resolution between any two calls to `now`. | ||
public var minimumResolution: Swift.Duration { | ||
var resolution = timespec() | ||
|
||
let result = clock_getres(CLOCK_REALTIME, &resolution) | ||
|
||
guard result == 0 else { | ||
fatalError("Failed to get realtime clock resolution in clock_getres(), errno = \(errno)") | ||
} | ||
|
||
let seconds = Int64(resolution.tv_sec) | ||
let attoseconds = Int64(resolution.tv_nsec) * 1_000_000_000 | ||
|
||
return Duration(secondsComponent: seconds, attosecondsComponent: attoseconds) | ||
} | ||
|
||
/// The current continuous instant. | ||
public static var now: InternalUTCClock.Instant { | ||
var currentTime = timespec() | ||
let result = clock_gettime(CLOCK_REALTIME, ¤tTime) | ||
|
||
guard result == 0 else { | ||
fatalError("Failed to get current time in clock_gettime(), errno = \(errno)") | ||
} | ||
|
||
let seconds = Int64(currentTime.tv_sec) | ||
let attoseconds = Int64(currentTime.tv_nsec) * 1_000_000_000 | ||
|
||
return InternalUTCClock.Instant(_value: Duration(secondsComponent: seconds, attosecondsComponent: attoseconds)) | ||
} | ||
|
||
/// Suspend task execution until a given deadline within a tolerance. | ||
/// If no tolerance is specified then the system may adjust the deadline | ||
/// to coalesce CPU wake-ups to more efficiently process the wake-ups in | ||
/// a more power efficient manner. | ||
/// | ||
/// If the task is canceled before the time ends, this function throws | ||
/// `CancellationError`. | ||
/// | ||
/// This function doesn't block the underlying thread. | ||
public func sleep( | ||
until deadline: Instant, tolerance: Swift.Duration? = nil | ||
) async throws { | ||
try await Task.sleep(until: deadline, tolerance: tolerance, clock: .internalUTC) | ||
} | ||
} | ||
|
||
extension InternalUTCClock.Instant: InstantProtocol { | ||
public static var now: InternalUTCClock.Instant { InternalUTCClock.now } | ||
|
||
public func advanced(by duration: Swift.Duration) -> InternalUTCClock.Instant { | ||
return InternalUTCClock.Instant(_value: _value + duration) | ||
} | ||
|
||
public func duration(to other: InternalUTCClock.Instant) -> Swift.Duration { | ||
other._value - _value | ||
} | ||
|
||
public func hash(into hasher: inout Hasher) { | ||
hasher.combine(_value) | ||
} | ||
|
||
public static func == ( | ||
_ lhs: InternalUTCClock.Instant, _ rhs: InternalUTCClock.Instant | ||
) -> Bool { | ||
return lhs._value == rhs._value | ||
} | ||
|
||
public static func < ( | ||
_ lhs: InternalUTCClock.Instant, _ rhs: InternalUTCClock.Instant | ||
) -> Bool { | ||
return lhs._value < rhs._value | ||
} | ||
|
||
@inlinable | ||
public static func + ( | ||
_ lhs: InternalUTCClock.Instant, _ rhs: Swift.Duration | ||
) -> InternalUTCClock.Instant { | ||
lhs.advanced(by: rhs) | ||
} | ||
|
||
@inlinable | ||
public static func += ( | ||
_ lhs: inout InternalUTCClock.Instant, _ rhs: Swift.Duration | ||
) { | ||
lhs = lhs.advanced(by: rhs) | ||
} | ||
|
||
@inlinable | ||
public static func - ( | ||
_ lhs: InternalUTCClock.Instant, _ rhs: Swift.Duration | ||
) -> InternalUTCClock.Instant { | ||
lhs.advanced(by: .zero - rhs) | ||
} | ||
|
||
@inlinable | ||
public static func -= ( | ||
_ lhs: inout InternalUTCClock.Instant, _ rhs: Swift.Duration | ||
) { | ||
lhs = lhs.advanced(by: .zero - rhs) | ||
} | ||
|
||
@inlinable | ||
public static func - ( | ||
_ lhs: InternalUTCClock.Instant, _ rhs: InternalUTCClock.Instant | ||
) -> Swift.Duration { | ||
rhs.duration(to: lhs) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
@testable import DateTime | ||
import XCTest | ||
|
||
final class DateTimeTests: XCTestCase { | ||
func testExample() throws { | ||
let time = InternalUTCClock().measure { | ||
print("Time now: \(InternalUTCClock.now)") | ||
print("Time now: \(InternalUTCClock.now._value.components)") | ||
print("Resolution: \(InternalUTCClock().minimumResolution)") | ||
} | ||
print("Elapsed time in nanoseconds \(time.components.attoseconds / 1_000_000_000)") | ||
let time2 = InternalUTCClock().measure { | ||
_ = 47 | ||
} | ||
print("Elapsed time in nanoseconds for empty closure \(time2.components.attoseconds / 1_000_000_000)") | ||
// This is an example of a functional test case. | ||
// Use XCTAssert and related functions to verify your tests produce the correct | ||
// results. | ||
} | ||
} |