Created
June 19, 2022 14:48
-
-
Save LK-Simon/d1f5979c54a064871e4eea7ff2e4abf8 to your computer and use it in GitHub Desktop.
High Precision "Mach Timer" for MacOS and iOS (Swift implementation)
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
import Foundation | |
enum MachTimerError: Error { | |
case TimebaseInfoError // Only thrown where we cannot initialize the Mach Timer (shouldn't ever happen though) | |
} | |
struct MachTimer { | |
// We need to know whether or not the Timer is still running or Stopped at the point of requesting a Result | |
enum MachTimerState { | |
case NotRunning | |
case Running | |
} | |
// Object to encapsulate a Result and provide basic conversion to Milliseconds and Seconds from NAnoseconds | |
struct MachTimerResult { | |
var nanos: UInt64 // Original Result is in Nanoseconds | |
init(nanos: UInt64) { // We must provide a Nanosecond Result on Initialization | |
self.nanos = nanos | |
} | |
var millis: Double { // Return Result in Milliseconds | |
get { | |
return Double(self.nanos) / 1_000_00 | |
} | |
} | |
var seconds: Double { // Return Result in Seconds | |
get { | |
return Double(self.nanos) / 1_000_000_000 | |
} | |
} | |
} | |
var state: MachTimerState = .NotRunning | |
var startTime: UInt64 = 0 | |
var stopTime: UInt64 = 0 | |
let numer: UInt64 | |
let denom: UInt64 | |
init() throws { | |
var info = mach_timebase_info(numer: 0, denom: 0) | |
let status = mach_timebase_info(&info) | |
if status != KERN_SUCCESS { | |
throw MachTimerError.TimebaseInfoError | |
} | |
self.numer = UInt64(info.numer) | |
self.denom = UInt64(info.denom) | |
} | |
mutating func start(refTime: UInt64? = nil) { | |
let now: UInt64 = mach_absolute_time() // Always get the Reference Time (we might need to rely on it if no refTime is given) | |
let ref: UInt64 = refTime ?? now // Use refTime if given, otherwise fall back to now | |
self.startTime = ref | |
self.state = .Running | |
} | |
mutating func stop(refTime: UInt64? = nil) -> MachTimerResult { | |
let now: UInt64 = mach_absolute_time() // Always get the Reference Time (we might need to rely on it if no refTime is given) | |
let ref: UInt64 = refTime ?? now // Use refTime if given, otherwise fall back to now | |
self.stopTime = ref | |
self.state = .NotRunning | |
return self.result(refTime: self.stopTime) | |
} | |
mutating func result(refTime: UInt64? = nil) -> MachTimerResult { | |
let now: UInt64 = mach_absolute_time() // Always get the Reference Time (we might need to rely on it if no refTime is given) | |
let ref: UInt64 = self.state == .Running ? refTime ?? now : stopTime // If Running, use Now or refTime. If NOT Running, use stopTime | |
return MachTimerResult(nanos: ((ref - self.startTime) * self.numer) / self.denom) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
can you please tell me how to call in the view (like in the content view, or you need to make a class???
)