1

I'm using DispatchTime.now() to measure elapsed time between events. Sometimes it works correctly, but occasionally it generates values that are far below what I would expect.

My current usage:

var t = DispatchTime.now()
var pt = DispatchTime.now()

// called when an event happens
t = DispatchTime.now()
var elapsed = Double(t.uptimeNanoseconds - pt.uptimeNanoseconds)
elapsed *= 32768/1000000000
pt = t

Such that t and pt are current and previous times, elapsed takes the difference in nanoseconds, converts to double, and scales such that 1 second = 32768. When this technique fails the data recorded is about 100 times smaller than what is expected. The scaling is not the issue, I've checked the rawValue of t and pt. My assumption would be that the clock that runs DispatchTime is running at a slower speed, maybe because of debugging, but in general I would think iOS would compensate for something like this.

jonwooding
  • 39
  • 6
  • 1
    DispatchTime is meant for ... dispatch. It's subject to all kinds of deviations from wall ("regular") time, such as timer coalescing done by the OS. – Alexander Dec 15 '16 at 21:34
  • Thanks Alexander. Could you specify what you mean by dispatch? I saw an example of someone using DispatchTime and it seemed pretty clean but I suppose it isn't the best choice. Do you have a recommendation for measuring true time elapsed? – jonwooding Dec 15 '16 at 21:37
  • 1
    Grand Central Dispatch is the multi-threading framework for Swift. Using `DispatchTime` for anything other than specifying the time for `Dispatch` jobs is completely inappropriate, and will lead to wonky results like this. My solution here would depend on what exactly I'm looking to do, the kind of precision I want, the amount of performance I'm willing to pay for it, etc. – Alexander Dec 15 '16 at 21:39
  • Thanks I'll look into that framework so I don't misuse it again. I just need to measure elapsed time with a 32 kHz clock speed and accuracy of +- 10ms, should be easily achievable without any performance issues – jonwooding Dec 15 '16 at 21:40
  • Seems like `NSDate` will suffice for your need – Alexander Dec 15 '16 at 21:41
  • Convenient, I was just wrapping up some code to test if NSDate would work. I' – jonwooding Dec 15 '16 at 21:42
  • Personally, when I'm looking for a low-overhead way of calculating elapsed time, I use `CFAbsoluteTimeGetCurrent()` or `CACurrentMediaTime()`. – Rob Dec 15 '16 at 22:26

2 Answers2

0

As @AlexanderMomchliov suggested NSDate is a better approach than DispatchTime.

Implemented as:

var t: TimeInterval = 0
var pt: TimeInterval = NSDate().timeIntervalSinceReferenceDate

// called when an event happens
t = NSDate().timeIntervalSinceReferenceDate
var elapsed: Double = t - pt
elapsed *= 32768
pt = t
jonwooding
  • 39
  • 6
0

You are performing integer division which will result in inaccurate elapsed time:

elapsed *= 32768/1000000000

You should either wrap these as Double or end them with a decimal (i.e. 32768.0/1000000000.0):

elapsed *= Double(32768)/Double(1000000000)

Additionally, NSEC_PER_SEC is defined as a global variable as part of the Dispatch framework:

elapsed *= Double(32768)/Double(NSEC_PER_SEC)

NSDate or Date may be adjusted by the system and should not be used for reliably measuring elapsed time. DispatchTime or CACurrentMediaTime would be good solutions and are both based on mach absolute time. However, if the app is put in the background during measurement, then using Date would be a good fallback.

Also recommend checking out this question for further discussion.

BlueSolrac
  • 2,191
  • 2
  • 12
  • 9