PlateReverb
PlateReverb

Reputation: 664

mach_wait_until() Strange Behavior on iPad

I created a simple project to test out the functionality of mach_wait_until(). This code gives me an accurate printout of how precise the 1 second delay is. The console printout is virtually identical and extremely precise on both the iOS Simulator and on my iPad Air 2. However, on my iPad there is a HUGE delay, where the same 1 second delay takes about 100 seconds! And to add to the weirdness of it, the printout in the console says it only takes 1 second (with extremely low jitter and/or lag).

How can this be? Is there some timing conversion that I need to do for a physical iOS device when using mach_wait_until()?

class ViewController: UIViewController {

    override func viewDidLoad() {
      super.viewDidLoad()
      playNoteTest()
    }

    var start = mach_absolute_time()
    var end = mach_absolute_time()

    func playNoteTest() {
      let when = mach_absolute_time() + 1000000000

      self.start = mach_absolute_time()
      mach_wait_until(when)
      self.end = mach_absolute_time()
      let timeDelta = (self.end - self.start)
      let newTimeDelta = Double(timeDelta) / 1000000000.0
      print("Delta Time = \(newTimeDelta)")

      playNoteTest()
    }
}

Upvotes: 0

Views: 610

Answers (1)

Paulw11
Paulw11

Reputation: 114975

mach_absolute_time units are CPU dependent. You need to multiply by a device-specific constant in order to get real-world units. It is discussed in this Tech Q&A from Apple.

Here is some playground code that demonstrates the idea:

import PlaygroundSupport
import Foundation

PlaygroundPage.current.needsIndefiniteExecution = true

class TimeBase {
    static let NANOS_PER_USEC: UInt64 = 1000
    static let NANOS_PER_MILLISEC: UInt64 = 1000 * NANOS_PER_USEC
    static let NANOS_PER_SEC: UInt64 = 1000 * NANOS_PER_MILLISEC

    static var timebaseInfo: mach_timebase_info! = {
        var tb = mach_timebase_info(numer: 0, denom: 0)
        let status = mach_timebase_info(&tb)
        if status == KERN_SUCCESS {
            return tb
        } else {
            return nil
        }
    }()

    static func toNanos(abs:UInt64) -> UInt64 {
        return (abs * UInt64(timebaseInfo.numer)) / UInt64(timebaseInfo.denom)      
    }

    static func toAbs(nanos:UInt64) -> UInt64 {
        return (nanos * UInt64(timebaseInfo.denom)) / UInt64(timebaseInfo.numer)
    }

}

let duration = TimeBase.toAbs(nanos: 10 * TimeBase.NANOS_PER_SEC)

DispatchQueue.global(qos: .userInitiated).async {

    print("Start")
    let start = mach_absolute_time()
    mach_wait_until(start+duration)
    let stop = mach_absolute_time()

    let elapsed = stop-start
    let elapsedNanos = TimeBase.toNanos(abs: elapsed)
    let elapsedSecs = elapsedNanos/TimeBase.NANOS_PER_SEC
    print("Elapsed nanoseconds = \(elapsedNanos)")
    print("Elapsed seconds = \(elapsedSecs)")

}

Upvotes: 1

Related Questions