Is there a way to determine how much time a method needs to execute (in milliseconds)?
-
2Are you by any chance asking because you want to find out what you can optimize to make it faster? – Mike Dunlavey Jan 25 '10 at 02:00
-
1Yes, I'm using an UIWebView that is loading some pages. I want to optimize the pageloading by checking the time the method needs to load page 1 to page 10. – dan Jan 25 '10 at 02:03
-
2This appears to be a duplicate of this question: http://stackoverflow.com/questions/889380/how-can-i-get-a-precise-time-for-example-in-milliseconds-in-objective-c – Brad Larson Jan 25 '10 at 02:12
-
@BradLarson While it appears to be a duplicate, the other question has the better answers, i.e. there the prominent answers are not suggesting to use (the incorrect) NSDate but instead explains well why NSDate is the wrong way to do for this purpose. – Thomas Tempelmann Jun 04 '16 at 13:39
20 Answers
NSDate *methodStart = [NSDate date];
/* ... Do whatever you need to do ... */
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"executionTime = %f", executionTime);
Swift:
let methodStart = NSDate()
/* ... Do whatever you need to do ... */
let methodFinish = NSDate()
let executionTime = methodFinish.timeIntervalSinceDate(methodStart)
print("Execution time: \(executionTime)")
Swift3:
let methodStart = Date()
/* ... Do whatever you need to do ... */
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
Easy to use and has sub-millisecond precision.

- 16,304
- 7
- 99
- 130

- 6,805
- 3
- 18
- 13
-
-
3@PeterWarbo NSTimeInterval is a typedef of double and is defined as seconds - see http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html – Ben Lings Nov 03 '11 at 14:50
-
5You can log this value with a %f - NSLog("executionTime = %f", executionTime); – Tony Jan 16 '12 at 05:24
-
1@Tony you forgot the @, `NSLog(@"executionTime = %f", executionTime);` – John Riselvato Apr 18 '13 at 18:30
-
6I just compared `NSDate` and `mach_absolute_time()` at around 30ms level. 27 vs. 29, 36 vs. 39, 43 vs. 45. `NSDate` was easier to use for me and the results were similar enough not to bother with `mach_absolute_time()`. – nevan king Jul 31 '13 at 20:58
-
9Anything based on NSDate is not safe for measuring passed time because the time can jump, even backwards. A much safer way is to use mach_absolute_time, as shown in many of the other answers here. This one should be downvoted for being a bad example. See also the related answer that explains this all in more detail: http://stackoverflow.com/a/30363702/43615 – Thomas Tempelmann Jun 04 '16 at 13:36
-
Swift one liner: `NSLog("Total time: %f", NSDate().timeIntervalSinceDate(methodStart))` – Tom Roggero Jun 08 '16 at 20:07
-
Or simply do `NSDate *startDate = [NSDate date]; // action; [startDate timeIntervalSinceNow]` – Daneo Jul 01 '16 at 08:14
-
1For more precise timing you might want to use `CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();` Since `CFAbsoluteTime` is `double`, it is very precise (probably much more than you care for), yet it is convenient to use: you get the result already in seconds (with decimal places), so no need for converting. – thetrutz Sep 28 '16 at 22:39
-
-
to get result really in MS without seconds (only milliseconds): https://stackoverflow.com/a/49140242/7767664 – user924 Mar 06 '18 at 21:32
-
@thetrutz `CFAbsoluteTimeGetCurrent` is not safe as well as `NSDate` for benchmarking – Alex Nazarov Oct 22 '20 at 08:46
-
@AlexNazarsky please elaborate. The problem with NSDate is, that it will allocate an object, which is very slow (200-300ns?), whereas CFAbsoluteTimeGetCurrent() does not. But honestly I did not test, but got this info from: M. Weiher: iOS and macOS Performance Tuning. – thetrutz Oct 23 '20 at 09:13
-
@thetrutz the problem is `NSDate` depends on time zones, daylight savings, leap seconds, etc, unlike mach_absolute_time/CACurrentMediaTime. – Alex Nazarov Oct 28 '20 at 09:06
-
@AlexNazarsky I can't follow your answers. You said, CFAbsoluteTimeGetCurrent is not safe, I wonder why? You said, `NSDate` depends on time zones. But it does not. It represents a point in time with underlying `Double` (seconds since reference date). So it holds the same information as the double from `CFAbsoluteTimeGetCurrent`, but instead of being a `Double` `NSDate`s are objects, which require time for allocation, which is slow (in the nanoseconds) and could affect your measurement, whereas `CFAbsoluteTimeGetCurrent` just returns the double with no extra allocation. – thetrutz Oct 29 '20 at 12:55
-
@thetrutz 1. It's explicitly described here https://developer.apple.com/documentation/corefoundation/1543542-cfabsolutetimegetcurrent 2. You can just check it – print `CFAbsoluteTimeGetCurrent` and `CACurrentMediaTime` values, change the system date (for example), and check again. In the first case, you will get a negative number of seconds, in the second – actual value. – Alex Nazarov Oct 30 '20 at 15:40
-
@AlexNazarsky, that you for the explanation! To sum up: CFAbsoluteTimeGetCurrent is not safe when the system clock is set by the user or via a time server (rare). CACurrentMediaTime is not safe, when the device is put to sleep (rare). NSDate is bad because of the allocation time. NSDate is independent of leap seconds/time zones/daylight savings - that is, what the calendar is for. – thetrutz Oct 31 '20 at 20:28
Here are two one-line macros that I use:
#define TICK NSDate *startTime = [NSDate date]
#define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
Use it like this:
TICK;
/* ... Do Some Work Here ... */
TOCK;

- 3,055
- 1
- 20
- 21
-
6What makes this so good, is that tick-tock is such a memorable phrase that logging almost requires no thought. – John Riselvato Feb 07 '14 at 18:02
-
32`#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])` makes this answer also return which function the timer was used in. I found this useful if I used the TICK TOCK to time multiple functions. – golmschenk Mar 13 '14 at 22:00
-
4Great idea @golmschenk! You can also look into `__PRETTY_FUNCTION__` and `__LINE__` if you want more detailed information. – Ron Mar 17 '14 at 07:22
-
For fine-grained timing on OS X, you should use mach_absolute_time( )
declared in <mach/mach_time.h>
:
#include <mach/mach_time.h>
#include <stdint.h>
// Do some stuff to setup for timing
const uint64_t startTime = mach_absolute_time();
// Do some stuff that you want to time
const uint64_t endTime = mach_absolute_time();
// Time elapsed in Mach time units.
const uint64_t elapsedMTU = endTime - startTime;
// Get information for converting from MTU to nanoseconds
mach_timebase_info_data_t info;
if (mach_timebase_info(&info))
handleErrorConditionIfYoureBeingCareful();
// Get elapsed time in nanoseconds:
const double elapsedNS = (double)elapsedMTU * (double)info.numer / (double)info.denom;
Of course the usual caveats about fine-grained measurements apply; you're probably best off invoking the routine under test many times, and averaging/taking a minimum/some other form of processing.
Additionally, please note that you may find it more useful to profile your application running using a tool like Shark. This won't give you exact timing information, but it will tell you what percentage of the application's time is being spent where, which is often more useful (but not always).

- 103,815
- 19
- 183
- 269
There is a convenient wrapper for mach_absolute_time()
– it's a CACurrentMediaTime()
function from CoreAnimation
framework.
Unlike
NSDate
orCFAbsoluteTimeGetCurrent()
offsets,mach_absolute_time()
andCACurrentMediaTime()
are based on the internal host clock, a precise, monatomic measure, and not subject to changes in the external time reference, such as those caused by time zones, daylight savings, or leap seconds.
ObjC
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
Swift
import QuartzCore
let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")

- 1,178
- 8
- 16
-
4I think this answer deserves more upvotes. It's way better than using `NSDate`. – average Joe May 14 '19 at 08:31
-
-
1@EzekielElin – no, `CFAbsoluteTimeGetCurrent` "may decrease due to synchronization with external time references or due to an explicit user change of the clock" according Apple documentation, so it doesn't suit for benchmarking – Alex Nazarov Oct 22 '20 at 08:44
In Swift, I'm using:
In my Macros.swift I just added
var startTime = NSDate()
func TICK(){ startTime = NSDate() }
func TOCK(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__){
println("\(function) Time: \(startTime.timeIntervalSinceNow)\nLine:\(line) File: \(file)")
}
you can now just call anywhere
TICK()
// your code to be tracked
TOCK()
Swift 5.0
var startTime = NSDate()
func TICK(){ startTime = NSDate() }
func TOCK(function: String = #function, file: String = #file, line: Int = #line){
print("\(function) Time: \(startTime.timeIntervalSinceNow)\nLine:\(line) File: \(file)")
}
- this code is based on Ron's code translate to Swift, he has the credits
- I'm using start date at global level, any suggestion to improve are welcome

- 9,286
- 3
- 31
- 48

- 4,540
- 1
- 25
- 25
-
1This should be `\(-startTime.timeIntervalSinceNow)` (notice the negative) – Snowman Jan 08 '16 at 21:47
I know this is an old one but even I found myself wandering past it again, so I thought I'd submit my own option here.
Best bet is to check out my blog post on this: Timing things in Objective-C: A stopwatch
Basically, I wrote a class that does stop watching in a very basic way but is encapsulated so that you only need to do the following:
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
And you end up with:
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
in the log...
Again, check out my post for a little more or download it here: MMStopwatch.zip

- 2,591
- 1
- 25
- 20
I use macros based on Ron's solution.
#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])
For lines of code:
TICK(TIME1);
/// do job here
TOCK(TIME1);
we'll see in console something like: TIME1: 0.096618

- 1
- 1

- 219
- 4
- 9
-
Your answer is not really that much different from Ron's answer and also I somehow fail to see in what way it is better? – NoDataDumpNoContribution Jan 25 '16 at 21:38
-
2You can't use @Ron's solution inside one context twice. This is main reason for this macros. – Sergey Teryokhin Jan 25 '16 at 23:30
I use very minimal, one page class implementation inspired by code from this blog post:
#import <mach/mach_time.h>
@interface DBGStopwatch : NSObject
+ (void)start:(NSString *)name;
+ (void)stop:(NSString *)name;
@end
@implementation DBGStopwatch
+ (NSMutableDictionary *)watches {
static NSMutableDictionary *Watches = nil;
static dispatch_once_t OnceToken;
dispatch_once(&OnceToken, ^{
Watches = @{}.mutableCopy;
});
return Watches;
}
+ (double)secondsFromMachTime:(uint64_t)time {
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
return (double)time * (double)timebase.numer /
(double)timebase.denom / 1e9;
}
+ (void)start:(NSString *)name {
uint64_t begin = mach_absolute_time();
self.watches[name] = @(begin);
}
+ (void)stop:(NSString *)name {
uint64_t end = mach_absolute_time();
uint64_t begin = [self.watches[name] unsignedLongLongValue];
DDLogInfo(@"Time taken for %@ %g s",
name, [self secondsFromMachTime:(end - begin)]);
[self.watches removeObjectForKey:name];
}
@end
The usage of it is very simple:
- just call
[DBGStopwatch start:@"slow-operation"];
at the beginning - and then
[DBGStopwatch stop:@"slow-operation"];
after the finish, to get the time

- 1,718
- 25
- 28
I use this code:
#import <mach/mach_time.h>
float TIME_BLOCK(NSString *key, void (^block)(void)) {
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS)
{
return -1.0;
}
uint64_t start = mach_absolute_time();
block();
uint64_t end = mach_absolute_time();
uint64_t elapsed = end - start;
uint64_t nanos = elapsed * info.numer / info.denom;
float cost = (float)nanos / NSEC_PER_SEC;
NSLog(@"key: %@ (%f ms)\n", key, cost * 1000);
return cost;
}
You can get really fine timing (seconds.parts of seconds) using this StopWatch class. It uses the high-precision timer in the iPhone. Using NSDate will only get you second(s) accuracy. This version is designed specifically for autorelease and objective-c. I have a c++ version as well if needed. You can find the c++ version here.
StopWatch.h
#import <Foundation/Foundation.h>
@interface StopWatch : NSObject
{
uint64_t _start;
uint64_t _stop;
uint64_t _elapsed;
}
-(void) Start;
-(void) Stop;
-(void) StopWithContext:(NSString*) context;
-(double) seconds;
-(NSString*) description;
+(StopWatch*) stopWatch;
-(StopWatch*) init;
@end
StopWatch.m
#import "StopWatch.h"
#include <mach/mach_time.h>
@implementation StopWatch
-(void) Start
{
_stop = 0;
_elapsed = 0;
_start = mach_absolute_time();
}
-(void) Stop
{
_stop = mach_absolute_time();
if(_stop > _start)
{
_elapsed = _stop - _start;
}
else
{
_elapsed = 0;
}
_start = mach_absolute_time();
}
-(void) StopWithContext:(NSString*) context
{
_stop = mach_absolute_time();
if(_stop > _start)
{
_elapsed = _stop - _start;
}
else
{
_elapsed = 0;
}
NSLog([NSString stringWithFormat:@"[%@] Stopped at %f",context,[self seconds]]);
_start = mach_absolute_time();
}
-(double) seconds
{
if(_elapsed > 0)
{
uint64_t elapsedTimeNano = 0;
mach_timebase_info_data_t timeBaseInfo;
mach_timebase_info(&timeBaseInfo);
elapsedTimeNano = _elapsed * timeBaseInfo.numer / timeBaseInfo.denom;
double elapsedSeconds = elapsedTimeNano * 1.0E-9;
return elapsedSeconds;
}
return 0.0;
}
-(NSString*) description
{
return [NSString stringWithFormat:@"%f secs.",[self seconds]];
}
+(StopWatch*) stopWatch
{
StopWatch* obj = [[[StopWatch alloc] init] autorelease];
return obj;
}
-(StopWatch*) init
{
[super init];
return self;
}
@end
The class has a static stopWatch
method that returns an autoreleased object.
Once you call start
, use the seconds
method to get the elapsed time. Call start
again to restart it. Or stop
to stop it. You can still read the time (call seconds
) anytime after calling stop
.
Example In A Function (Timing call of execution)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}

- 3,387
- 2
- 18
- 28
-
Your "only seconds accuracy" is incorrect. While the whole part of a NSTimeInterval is seconds, it's a double. – Steven Fisher Jan 02 '17 at 19:24
OK, if your objective is to find out what you can fix to make it faster, that's a little different goal. Measuring the time that functions take is a good way to find out if what you did made a difference, but to find out what to do you need a different technique. This is what I recommend, and I know you can do it on iPhones.
Edit: Reviewers suggested I elaborate the answer, so I'm trying to think of a brief way to say it.
Your overall program takes enough clock time to bother you. Suppose that's N seconds.
You're assuming you can speed it up. The only way you can do that is by making it not do something it's doing in that time, accounting for m seconds.
You don't initially know what that thing is. You can guess, as all programmers do, but it could easily be something else. Whatever it is, here's how you can find it:
Since that thing, whatever it is, accounts for fraction m/N of the time, that means if you pause it at random the probability is m/N that you will catch it in the act of doing that thing. Of course it might be doing something else, but pause it and see what it's doing.
Now do it again. If you see it doing that same thing again, you can be more suspicious.
Do it 10 times, or 20. Now if you see it doing some particular thing (no matter how you describe it) on multiple pauses, that you can get rid of, you know two things. You know very roughly what fraction of time it takes, but you know very exactly what to fix.
If you also want to know very exactly how much time will be saved, that's easy. Measure it before, fix it, and measure it after. If you're really disappointed, back out the fix.
Do you see how this is different from measuring? It's finding, not measuring. Most profiling is based on measuring as exactly as possible how much time is taken, as if that's important, and hand-waves the problem of identifying what needs to be fixed. Profiling does not find every problem, but this method does find every problem, and it's the problems you don't find that hurt you.

- 40,059
- 14
- 91
- 135
An example of fine-grained timing using mach_absolute_time()
in Swift 4:
let start = mach_absolute_time()
// do something
let elapsedMTU = mach_absolute_time() - start
var timebase = mach_timebase_info()
if mach_timebase_info(&timebase) == 0 {
let elapsed = Double(elapsedMTU) * Double(timebase.numer) / Double(timebase.denom)
print("render took \(elapsed)")
}
else {
print("timebase error")
}

- 4,903
- 1
- 27
- 30
I use this:
clock_t start, end;
double elapsed;
start = clock();
//Start code to time
//End code to time
end = clock();
elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
NSLog(@"Time: %f",elapsed);
But I'm not sure about CLOCKS_PER_SEC on the iPhone. You might want to leave it off.

- 12,611
- 5
- 45
- 62
Here is another way, in Swift, to do that using the defer keyword
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
From Apple's docs: A defer statement is used for executing code just before transferring program control outside of the scope that the defer statement appears in.
This is similar to a try/finally block with the advantage of having the related code grouped.

- 690
- 6
- 13
I use this in my utils library (Swift 4.2):
public class PrintTimer {
let start = Date()
let name: String
public init(file: String=#file, line: Int=#line, function: String=#function, name: String?=nil) {
let file = file.split(separator: "/").last!
self.name = name ?? "\(file):\(line) - \(function)"
}
public func done() {
let end = Date()
print("\(self.name) took \((end.timeIntervalSinceReferenceDate - self.start.timeIntervalSinceReferenceDate).roundToSigFigs(5)) s.")
}
}
... then call in a method like:
func myFunctionCall() {
let timer = PrintTimer()
// ...
timer.done()
}
... which in turn looks like this in the console after running:
MyFile.swift:225 - myFunctionCall() took 1.8623 s.
Not as concise as TICK/TOCK above, but it is clear enough to see what it is doing and automatically includes what is being timed (by file, line at the start of the method, and function name). Obviously if I wanted more detail (ex, if I'm not just timing a method call as is the usual case but instead am timing a block within that method) I can add the "name="Foo"" parameter on the PrintTimer init to name it something besides the defaults.

- 167
- 1
- 6
Since you want to optimize time moving from one page to another in a UIWebView, does it not mean you really are looking to optimize the Javascript used in loading these pages?
To that end, I'd look at a WebKit profiler like that talked about here:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Another approach would be to start at a high level, and think how you can design the web pages in question to minimize load times using AJAX style page loading instead of refreshing the whole webview each time.

- 74,769
- 26
- 128
- 150
struct TIME {
static var ti = mach_timebase_info()
static var k: Double = 1
static var mach_stamp: Double {
if ti.denom == 0 {
mach_timebase_info(&ti)
k = Double(ti.numer) / Double(ti.denom) * 1e-6
}
return Double(mach_absolute_time()) * k
}
static var stamp: Double { return NSDate.timeIntervalSinceReferenceDate() * 1000 }
}
do {
let mach_start = TIME.mach_stamp
usleep(200000)
let mach_diff = TIME.mach_stamp - mach_start
let start = TIME.stamp
usleep(200000)
let diff = TIME.stamp - start
print(mach_diff, diff)
}

- 16,722
- 2
- 40
- 59
Here's a Swift 3 solution for bisecting code anywhere to find a long running process.
var increment: Int = 0
var incrementTime = NSDate()
struct Instrumentation {
var title: String
var point: Int
var elapsedTime: Double
init(_ title: String, _ point: Int, _ elapsedTime: Double) {
self.title = title
self.point = point
self.elapsedTime = elapsedTime
}
}
var elapsedTimes = [Instrumentation]()
func instrument(_ title: String) {
increment += 1
let incrementedTime = -incrementTime.timeIntervalSinceNow
let newPoint = Instrumentation(title, increment, incrementedTime)
elapsedTimes.append(newPoint)
incrementTime = NSDate()
}
Usage: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
Sample output:-
ELAPSED TIMES [MyApp.SomeViewController.Instrumentation(title: "Start View Did Load", point: 1, elapsedTime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation(title: "Finished Adding SubViews", point: 2, elapsedTime: 0.010585010051727295), MyApp.SomeViewController.Instrumentation(title: "View Did Appear", point: 3, elapsedTime: 0.56564098596572876)]

- 1,199
- 19
- 82
- 151
many answers are weird and don't really give result in milliseconds (but in seconds or anything else):
here what I use to get MS (MILLISECONDS):
Swift:
let startTime = NSDate().timeIntervalSince1970 * 1000
// your Swift code
let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime
print("time code execution \(endTimeMinStartTime) ms")
Objective-C:
double startTime = [[NSDate date] timeIntervalSince1970] * 1000.0;
// your Objective-C code
double endTimeMinusStartTime = [[NSDate date] timeIntervalSince1970] * 1000.0 - startTime;
printf("time code execution %f ms\n", endTimeMinusStartTime );

- 8,146
- 7
- 57
- 139
For Swift 4, add as a Delegate to your class:
public protocol TimingDelegate: class {
var _TICK: Date?{ get set }
}
extension TimingDelegate {
var TICK: Date {
_TICK = Date()
return(_TICK)!
}
func TOCK(message: String) {
if (_TICK == nil){
print("Call 'TICK' first!")
}
if (message == ""){
print("\(Date().timeIntervalSince(_TICK!))")
}
else{
print("\(message): \(Date().timeIntervalSince(_TICK!))")
}
}
}
Add to our class:
class MyViewcontroller: UIViewController, TimingDelegate
Then add to your class:
var _TICK: Date?
When you want to time something, start with:
TICK
And end with:
TOCK("Timing the XXX routine")