Measure elapsed time in Swift
This is a handy timer class based on CoreFoundation
s CFAbsoluteTime
:
import CoreFoundation
class ParkBenchTimer {
let startTime: CFAbsoluteTime
var endTime: CFAbsoluteTime?
init() {
startTime = CFAbsoluteTimeGetCurrent()
}
func stop() -> CFAbsoluteTime {
endTime = CFAbsoluteTimeGetCurrent()
return duration!
}
var duration: CFAbsoluteTime? {
if let endTime = endTime {
return endTime - startTime
} else {
return nil
}
}
}
You can use it like this:
let timer = ParkBenchTimer()
// ... a long runnig task ...
print("The task took \(timer.stop()) seconds.")
Swift 4 shortest answer:
let startingPoint = Date()
// ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
It will print you something like 1.02107906341553 seconds elapsed (time of course will vary depending on the task, I'm just showing this for you guys to see the decimal precision level for this measurement).
Hope it helps someone in Swift 4 from now on!
Update
If you want to have a generic way of testing portions of code, I'd suggest the next snippet:
func measureTime(for closure: @autoclosure () -> Any) {
let start = CFAbsoluteTimeGetCurrent()
closure()
let diff = CFAbsoluteTimeGetCurrent() - start
print("Took \(diff) seconds")
}
Usage
measureTime(for: <insert method signature here>)
Console log
Took xx.xxxxx seconds
Use clock
, ProcessInfo.systemUptime
, or DispatchTime
for simple start-up time.
There are, as far as I know, at least ten ways to measure elapsed time:
Monotonic Clock based:
ProcessInfo.systemUptime
.mach_absolute_time
withmach_timebase_info
as mentioned in this answer.clock()
in POSIX standard.times()
in POSIX standard. (Too complicated since we need to consider user-time v.s. system-time, and child processes are involved.)DispatchTime
(a wrapper around Mach time API) as mentioned by JeremyP in accepted answer.CACurrentMediaTime()
.
Wall Clock based:
(never use those for metrics: see below why)
NSDate
/Date
as mentioned by others.CFAbsoluteTime
as mentioned by others.DispatchWallTime
.gettimeofday()
in POSIX standard.
Option 1, 2 and 3 are elaborated below.
Option 1: Process Info API in Foundation
do {
let info = ProcessInfo.processInfo
let begin = info.systemUptime
// do something
let diff = (info.systemUptime - begin)
}
where diff:NSTimeInterval
is the elapsed time by seconds.
Option 2: Mach C API
do {
var info = mach_timebase_info(numer: 0, denom: 0)
mach_timebase_info(&info)
let begin = mach_absolute_time()
// do something
let diff = Double(mach_absolute_time() - begin) * Double(info.numer) / Double(info.denom)
}
where diff:Double
is the elapsed time by nano-seconds.
Option 3: POSIX clock API
do {
let begin = clock()
// do something
let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
where diff:Double
is the elapsed time by seconds.
Why Not Wall-Clock Time for Elapsed Time?
In documentation of CFAbsoluteTimeGetCurrent
:
Repeated calls to this function do not guarantee monotonically increasing results.
Reason is similar to currentTimeMillis
vs nanoTime
in Java:
You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected. This correction might either happen manually, or in the case of most machines, there's a process that runs and continually issues small corrections to the system clock ("wall clock"). These tend to happen often. Another such correction happens whenever there is a leap second.
Here CFAbsoluteTime
provides wall clock time instead of start-up
time. NSDate
is wall clock time as well.
Update
With Swift 5.7, I think everything below becomes obsolete. Swift 5.7 introduces the concept of a Clock which appears to have a function designed to do exactly what is required here.
I'll update with an example as soon as I've got Swift 5.7 and have the time to rework it.
Here's a Swift function I wrote to measure Project Euler problems in Swift
As of Swift 3, there is now a version of Grand Central Dispatch that is "swiftified". So the correct answer is probably to use the DispatchTime API.
My function would look something like:
// Swift 3
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer
{
print("Evaluating problem \(problemNumber)")
let start = DispatchTime.now() // <<<<<<<<<< Start time
let myGuess = problemBlock()
let end = DispatchTime.now() // <<<<<<<<<< end time
let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds // <<<<< Difference in nano seconds (UInt64)
let timeInterval = Double(nanoTime) / 1_000_000_000 // Technically could overflow for long running tests
print("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
return theAnswer
}
Old answer
For Swift 1 and 2, my function uses NSDate:
// Swift 1
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer
{
println("Evaluating problem \(problemNumber)")
let start = NSDate() // <<<<<<<<<< Start time
let myGuess = problemBlock()
let end = NSDate() // <<<<<<<<<< end time
let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)
let timeInterval: Double = end.timeIntervalSinceDate(start) // <<<<< Difference in seconds (double)
println("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
return theAnswer
}
Note that using NSdate for timing functions is discouraged: "The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.".