如何准确logging一个方法的执行时间,以毫秒为单位?

有没有办法确定一个方法需要执行多less时间(以毫秒为单位)?

NSDate *methodStart = [NSDate date]; /* ... Do whatever you need to do ... */ NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime); 

迅速:

 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)") 

易于使用,并具有亚毫秒的精度。

以下是我使用的两个单行macros:

 #define TICK NSDate *startTime = [NSDate date] #define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow]) 

像这样使用它:

 TICK; /* ... Do Some Work Here ... */ TOCK; 

对于OS X上的精细时序,应该使用<mach/mach_time.h>声明的mach_absolute_time( )

 #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; 

当然,通常关于细粒度测量的警告也适用。 你可能最好的方法是多次调用被testing的例程,并且平均/采取最小/其他forms的处理。

此外,请注意,您可能会发现使用像Shark这样的工具来运行应用程序更加有用。 这不会给你准确的时间信息,但是它会告诉你在哪里花费了多less时间,这通常更有用(但并不总是)。

在Swift中,我正在使用:

在我刚刚添加的Macros.swift中

 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)") } 

你现在可以随时拨打电话

 TICK() // your code to be tracked TOCK() 
  • 这个代码是基于Ron的代码翻译成Swift的,他有学分
  • 我在全球范围内使用开始date,任何改善的build议都是值得欢迎的

我知道这是一个古老的,但即使我发现自己再次徘徊,所以我想我会在这里提交自己的select。

最好的办法是查看我的博客文章: Objective-C中的定时事物:秒表

基本上,我写了一个类,停止看一个非常基本的方式,但封装,所以你只需要做到以下几点:

 [MMStopwatchARC start:@"My Timer"]; // your work here ... [MMStopwatchARC stop:@"My Timer"]; 

最后你会得到:

 MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029] 

在日志中…

再次,看看我的post多一点或在这里下载: MMStopwatch.zip

我使用基于Ron的解决scheme的macros。

 #define TICK(XXX) NSDate *XXX = [NSDate date] #define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow]) 

对于代码行:

 TICK(TIME1); /// do job here TOCK(TIME1); 

我们将在控制台中看到类似于:TIME1:0.096618

您可以使用此StopWatch类获得非常好的计时(seconds.parts of seconds)。 它使用iPhone中的高精度计时器。 使用NSDate只会让你秒准确。 这个版本是专门为autorelease和objective-cdevise的。 如果需要,我也有一个C ++版本。 你可以在这里findc ++版本 。

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 

该类有一个静态stopWatch方法,返回一个自动释放对象。

一旦你调用start ,使用seconds方法来获得stream逝的时间。 请再次启动以重新启动它。 或者stop来停下来。 通话结束后,您仍可以随时读取通话时间(通话seconds )。

一个函数中的例子 (定时执行调用)

 -(void)SomeFunc { StopWatch* stopWatch = [StopWatch stopWatch]; [stopWatch Start]; ... do stuff [stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]]; } 

我用这个博客的代码启发了一个非常小的页面类实现:

 #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 %@ %gs", name, [self secondsFromMachTime:(end - begin)]); [self.watches removeObjectForKey:name]; } @end 

它的使用非常简单:

  • 只需调用[DBGStopwatch start:@"slow-operation"]; 在开始
  • 然后[DBGStopwatch stop:@"slow-operation"]; 完成后,获得时间

好的,如果你的目标是找出你能解决的问题,那么这个目标就有点不同了。 测量function的时间是一个很好的方法来确定你做了什么改变,但要找出你要做什么,你需要一个不同的技术。 这是我推荐的 ,我知道你可以在iPhone上做。

我使用这个:

 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); 

但我不确定iPhone上的CLOCKS_PER_SEC。 你可能想离开它。

我使用这个代码:

 #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; } 

既然你想优化在UIWebView中从一个页面移动到另一个页面的时间,这是不是说你真的想要优化用于加载这些页面的Javascript?

为此,我会看一下这里讨论的WebKit分析器:

http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/

另一种方法是从高层开始,考虑如何使用AJAX风格的页面加载来devise有问题的网页,以最小化加载时间,而不是每次刷新整个webview。

 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) } 

在Swift中,另一种方法是使用defer关键字

 func methodName() { let methodStart = Date() defer { let executionTime = Date().timeIntervalSince(methodStart) print("Execution time: \(executionTime)") } // do your stuff here } 

从Apple的文档 : 在将延迟语句出现的范围之外的程序控制转移之前,使用延迟语句执行代码。

这与try / finally块相似,具有相关代码分组的优点。

这里有一个Swift 3解决scheme,用于在任何地方平分代码以find长时间运行的进程。

 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() } 

用法: –

 instrument("View Did Appear") print("ELAPSED TIMES \(elapsedTimes)") 

示例输出: –

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)]