Introducing Timer.record(_ duration:), closes #114 (#133)

Motivation:

`Duration` is available starting Swift 5.7, and we
should probably support it in our convinience API.

Modifications:
- Timer.record(_ duration: Duration) implementation
- A unit test case
- Generated Linux tests
This commit is contained in:
Natik Gadzhi 2023-06-28 14:56:55 -07:00 committed by GitHub
parent 971ba26378
commit 13ea1fe7fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 0 deletions

View File

@ -74,3 +74,29 @@ extension Timer {
}
}
}
#if swift(>=5.7)
extension Timer {
/// Convenience for recording a duration based on ``Duration``.
///
/// `Duration` will be converted to an `Int64` number of nanoseconds, and then recorded with nanosecond precision.
///
/// - Parameters:
/// - duration: The `Duration` to record.
///
/// - Throws: `TimerError.durationToIntOverflow` if conversion from `Duration` to `Int64` of Nanoseconds overflowed.
@available(macOS 13, iOS 16, tvOS 15, watchOS 8, *)
@inlinable
public func record(_ duration: Duration) {
// `Duration` doesn't have a nice way to convert it nanoseconds or seconds,
// and manual conversion can overflow.
let seconds = duration.components.seconds.multipliedReportingOverflow(by: 1_000_000_000)
guard !seconds.overflow else { return self.recordNanoseconds(Int64.max) }
let nanoseconds = seconds.partialValue.addingReportingOverflow(duration.components.attoseconds / 1_000_000_000)
guard !nanoseconds.overflow else { return self.recordNanoseconds(Int64.max) }
self.recordNanoseconds(nanoseconds.partialValue)
}
}
#endif

View File

@ -29,6 +29,7 @@ extension MetricsExtensionsTests {
("testTimerWithTimeInterval", testTimerWithTimeInterval),
("testTimerWithDispatchTime", testTimerWithDispatchTime),
("testTimerWithDispatchTimeInterval", testTimerWithDispatchTimeInterval),
("testTimerDuration", testTimerDuration),
("testTimerUnits", testTimerUnits),
("testPreferDisplayUnit", testPreferDisplayUnit),
]

View File

@ -96,6 +96,38 @@ class MetricsExtensionsTests: XCTestCase {
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
}
func testTimerDuration() throws {
// Wrapping only the insides of the test case so that the generated
// tests on Linux in MetricsTests+XCTest don't complain that the func does not exist.
#if swift(>=5.7)
guard #available(iOS 16, macOS 13, tvOS 15, watchOS 8, *) else {
throw XCTSkip("Timer.record(_ duration: Duration) is not available on this platform")
}
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
let name = "timer-\(UUID().uuidString)"
let timer = Timer(label: name)
let duration = Duration(secondsComponent: 3, attosecondsComponent: 123_000_000_000_000_000)
let nanoseconds = duration.components.seconds * 1_000_000_000 + duration.components.attoseconds / 1_000_000_000
timer.record(duration)
// Record a Duration that would overflow,
// expect Int64.max to be recorded.
timer.record(Duration(secondsComponent: 10_000_000_000, attosecondsComponent: 123))
let testTimer = try metrics.expectTimer(timer)
XCTAssertEqual(testTimer.values.count, 2, "expected number of entries to match")
XCTAssertEqual(testTimer.values.first, nanoseconds, "expected value to match")
XCTAssertEqual(testTimer.values[1], Int64.max, "expected to record Int64.max if Durataion overflows")
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
#elseif swift(>=5.2)
throw XCTSkip("Timer.record(_ duration: Duration) is only available on Swift >=5.7")
#endif
}
func testTimerUnits() throws {
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)

View File

@ -64,6 +64,12 @@ fi
printf "\033[0;32mokay.\033[0m\n"
printf "=> Checking format... "
if [[ ! -x $(which swiftformat) ]]; then
printf "\033[0;31mswiftformat not found!\033[0m\n"
exit 1
fi
FIRST_OUT="$(git status --porcelain)"
swiftformat . > /dev/null 2>&1
SECOND_OUT="$(git status --porcelain)"