I am using the below code to use mach_wait_until() to wait for a specified period of time (in nanoseconds).
private func startTimerAndResume(){
let idealNanos: UInt64 = 1250130250 //1.25 seconds
let deadline = CFAbsoluteTime(mach_absolute_time() + (timeUnitsFor(nanos: idealNanos))/100)
let x = mach_absolute_time()
mach_wait_until(UInt64(deadline))
let y = mach_absolute_time()
var timeBaseInfo = mach_timebase_info_data_t()
mach_timebase_info(&timeBaseInfo)
let elapsedNanos = (y - x) * UInt64(timeBaseInfo.numer) / UInt64(timeBaseInfo.denom);
print("deadline (aka mach-abs-time + timeUnitsFor()) = \(deadline)")
print("(mach-abs-y)-(mach-abs-x) = \(y-x)")
print("error in time units = \((y-x)-(timeUnitsFor(nanos: idealNanos))/100)")
print("elapsed nanos actual = ", elapsedNanos)
print("elapsed nanos ideal = ", idealNanos)
print("error in nanoseconds = \(elapsedNanos - idealNanos)")
}
private func timeUnitsFor(nanos: UInt64)-> UInt64{
var timeBaseInfo = mach_timebase_info_data_t()
mach_timebase_info(&timeBaseInfo)
let numer: UInt64 = UInt64(timeBaseInfo.numer)
let denom: UInt64 = UInt64(timeBaseInfo.denom)
//elapsed time in nanoseconds = timUnits * (numer / denom) ... therefore ->
let timeUnits: UInt64 = (nanos*denom/numer)*(UInt64(100))//multiply by 100 to preserve decimal before truncation caused by UInt64() conversion
print("timeUnits = \((timeUnits)/100) for target nanos \(nanos) when numer = \(numer) and denom = \(denom)")
return timeUnits
}
When i run this on my actual iPhone device the error is usually around 1 milisecond and the output is this:
timeUnits = 30003126 for target nanos 1250130250 when numer = 125 and denom = 3
deadline (aka mach-abs-time + timeUnitsFor()) = 4025277628801.0
(mach-abs-y)-(mach-abs-x) = 30027213
timeUnits = 30003126 for target nanos 1250130250 when numer = 125 and denom = 3
error in time units = 24087
elapsed nanos actual = 1251133875
elapsed nanos ideal = 1250130250
error in nanoseconds = 1003625
However when I run this on my simulator the timer is consistently 70 to 74 milliseconds late, here is the output :
timeUnits = 1250130250 for target nanos 1250130250 when numer = 1 and denom = 1
deadline (aka mach-abs-time + timeUnitsFor()) = 691695760744956.0
(mach-abs-y)-(mach-abs-x) = 1322288698
timeUnits = 1250130250 for target nanos 1250130250 when numer = 1 and denom = 1
error in time units = 72158448
elapsed nanos actual = 1322288698
elapsed nanos ideal = 1250130250
error in nanoseconds = 72158448
I would like to know why the simulator is 70 to 74 milliseconds late every time. Am i doing the conversion between nanoseconds and mach time units wrong? Thanks
The simulator is not a clockcycle accurate arm emulator meant for clockcycle accurate testing. It is a build of iOS for Intel and shares the kernel with the rest of the host OS.
It's possible that your timers are getting coalesced in the simulator whereas they're not on device. Depending on your host configuration and runtime version, the simulator processes may be running at the Utility QoS tier.
So, the reason you're seeing a difference in timing is because of one or more of those reasons:
You should not be relying on getting control back within a specific window as that's not in the API contract. You will be scheduled at some point after that time has elapsed.