如何准确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)]