Measure elapsed time in Swift
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.".
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 ...
println("The task took \(timer.stop()) 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.