Skip to content

Instantly share code, notes, and snippets.

@LK-Simon
Created June 19, 2022 14:48
Show Gist options
  • Save LK-Simon/d1f5979c54a064871e4eea7ff2e4abf8 to your computer and use it in GitHub Desktop.
Save LK-Simon/d1f5979c54a064871e4eea7ff2e4abf8 to your computer and use it in GitHub Desktop.
High Precision "Mach Timer" for MacOS and iOS (Swift implementation)
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)
}
}
@NilaxanN
Copy link

can you please tell me how to call in the view (like in the content view, or you need to make a class???
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment