メソッドの実行に必要な時間(ミリ秒単位)を決定する方法はありますか?
メソッドの実行に必要な時間(ミリ秒単位)を決定する方法はありますか?
回答:
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)")
使いやすく、ミリ秒未満の精度があります。
NSLog(@"executionTime = %f", executionTime);
NSDate
しmach_absolute_time()
ました。27対29、36対39、43対45のNSDate
方が私には使いやすく、結果はと気にしないほど十分に似ていましたmach_absolute_time()
。
ここに私が使用する2つの1行のマクロがあります:
#define TICK NSDate *startTime = [NSDate date]
#define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
次のように使用します。
TICK;
/* ... Do Some Work Here ... */
TOCK;
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
この答えは、タイマーが使用された関数も返すようにします。TICKTOCKを使用して複数の関数の時間を計った場合、これは便利です。
__PRETTY_FUNCTION__
し、__LINE__
あなたがより詳細な情報が必要な場合。
OS Xできめ細かなタイミングを得るにmach_absolute_time( )
は、で宣言されたを使用する必要があります<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;
もちろん、きめの細かい測定に関する通常の警告が適用されます。おそらく、テスト対象のルーチンを何度も呼び出して、平均化/最小化/その他の形式の処理を行うことをお勧めします。
さらに、Sharkなどのツールを使用して実行中のアプリケーションをプロファイリングする方が便利な場合があることに注意してください。これは正確なタイミング情報を提供しませんが、アプリケーションの時間の何パーセントがどこで費やされているかを示します。
便利なラッパーがあり、mach_absolute_time()
それはCACurrentMediaTime()
関数です。
異なり
NSDate
、またはCFAbsoluteTimeGetCurrent()
オフセット、mach_absolute_time()
およびCACurrentMediaTime()
そのような時間帯、夏時間、またはうるう秒に起因するもののような外部時間基準の変化、内部のホスト・クロック、精密、単原子尺度ではなく、対象に基づいています。
ObjC
CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
迅速
let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
NSDate
ます。
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()
\(-startTime.timeIntervalSinceNow)
(ネガティブなことに注意してください)
これは古いものであることは知っていますが、自分が再びそれを通り過ぎていることに気付いたので、自分のオプションをここに提出したいと思いました。
最善の策は、これに関する私のブログ投稿をチェックすることです: Objective-Cでのタイミング:ストップウォッチ
基本的に、私は非常に基本的な方法で監視を停止するが、カプセル化されているクラスを作成しました。そのため、次のことだけを実行する必要があります。
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
そしてあなたは次のようになります:
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
ログに...
もう一度、もう少し私の投稿をチェックするか、ここからダウンロードしてください: MMStopwatch.zip
私はロンのソリューションに基づいたマクロを使用しています。
#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
私はこのブログ投稿のコードに触発された非常に最小限の1ページクラス実装を使用しています。
#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
使い方はとても簡単です:
[DBGStopwatch start:@"slow-operation"];
最初に電話するだけ[DBGStopwatch stop:@"slow-operation"];
フィニッシュ後、時間を得るためにこのStopWatchクラスを使用すると、非常に細かいタイミング(seconds.parts of seconds)を取得できます。iPhoneの高精度タイマーを使用しています。NSDateを使用すると、秒の精度しか得られません。このバージョンは、自動リリースとobjective-c用に特別に設計されています。必要に応じてc ++バージョンも持っています。 ここでc ++バージョンを見つけることができます。
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
メソッドを使用して経過時間を取得します。start
それを再起動するには、もう一度電話してください。またはそれstop
を停止します。呼び出したseconds
後でも、いつでも時刻を読み取る(呼び出し)ことができstop
ます。
関数の例 (実行のタイミング呼び出し)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}
私はこのコードを使用します:
#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;
}
私はこれを使います:
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についてはよくわかりません。オフにしておくことをお勧めします。
mach_absolute_time()
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")
}
OK、あなたの目的がそれをより速くするためにあなたが修正できるものを見つけることであるなら、それは少し異なる目標です。関数がかかる時間を測定することは、自分が何をしたかが違いを生んでいるかどうかを知るための良い方法ですが、何をすべきかを知るためには別のテクニックが必要です。これが私がお勧めする方法です。iPhoneでできることは知っています。
編集:査読者は私が答えを詳しく説明することを提案したので、私はそれを言う簡単な方法を考えようとしています。
あなたの全体的なプログラムはあなたを悩ませるために十分なクロック時間を必要とします。それがN秒だとします。
あなたはあなたがそれをスピードアップできると仮定しています。あなたがそれを行うことができる唯一の方法は、m秒を考慮して、その時間に行っていることを行わないようにすることです。
最初はそれが何であるかを知りません。すべてのプログラマーがそうであるように、あなたは推測することができますが、それは簡単に他のものになる可能性があります。それが何であれ、それを見つける方法は次のとおりです。
そのことは、それが何であれ、時間の分数m / Nを占めるので、ランダムに一時停止すると、確率でm / Nになり、そのことを実行する過程でそれをキャッチします。もちろん、それは何か他のことをしているかもしれませんが、それを一時停止して、それが何をしているかを見てください。
もう一度やり直してください。それが同じことをもう一度実行しているのを見た場合は、さらに疑わしいことがあります。
それを10回、つまり20回実行します。今度は、特定のことを(どのように説明したかに関係なく)複数の一時停止で実行して、取り除くことができる場合、2つのことがわかります。あなたはそれがどのくらいの時間を要するかを大まかに知っていますが、何を修正すべきかを非常に正確に知っています。どれだけの時間を節約できるかを正確
に知りたいのなら、それは簡単です。前に測定して修正し、後で測定します。本当にがっかりしている場合は、修正を取り消してください。
これが測定とどのように違うかわかりますか?それはだ測定、ない見つけます。ほとんどのプロファイリングは、まるでそれが重要であるかのように、どれだけの時間がかかるかを可能な限り正確に測定することに基づいており、修正する必要があるものを特定する問題を手振りします。プロファイリングですべての問題が見つかるわけではありませんが、この方法ではすべての問題が見つかるので、気にならないのはあなたが気づかない問題です。
Swiftで、deferキーワードを使用してそれを行う別の方法があります
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
Appleのドキュメントより:deferステートメントは、deferステートメントが出現するスコープの外でプログラム制御を転送する直前にコードを実行するために使用されます。
これはtry / finallyブロックに似ており、関連するコードがグループ化されるという利点があります。
私はこれを私のutilsライブラリ(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.")
}
}
...次に、次のようなメソッドを呼び出します。
func myFunctionCall() {
let timer = PrintTimer()
// ...
timer.done()
}
...実行すると、コンソールで次のようになります。
MyFile.swift:225 - myFunctionCall() took 1.8623 s.
上記のTICK / TOCKほど簡潔ではありませんが、それが何をしているかを確認するのに十分明確であり、(ファイル、メソッドの先頭の行、および関数名によって)計時されているものを自動的に含みます。明らかに、より詳細な情報が必要な場合(たとえば、通常のようにメソッド呼び出しのタイミングをとっているだけでなく、そのメソッド内のブロックのタイミングをとっている場合)、PrintTimer initに "name =" Foo ""パラメータを追加できます。デフォルト以外の名前を付けます。
UIWebViewのあるページから別のページへの移動時間を最適化したいので、これらのページのロードに使用されるJavascriptを最適化しようとしているわけではありませんか?
そのために、ここで話したようなWebKitプロファイラーを見てみましょう。
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
別のアプローチは、高レベルから開始し、問題のWebページを設計して、毎回Webビュー全体を更新するのではなく、AJAXスタイルのページロードを使用してロード時間を最小限に抑える方法を考えることです。
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 3ソリューションです。
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、lapsedTime:0.040504038333892822)、MyApp.SomeViewController.Instrumentation(title: "Finished Added SubViews"、point:2、lapsedTime:0.010585010051727295)、 MyApp.SomeViewController.Instrumentation(title: "ビューが表示されました"、ポイント:3、expededTime:0.56564098596572876)]
多くの答えは奇妙であり、実際にはミリ秒単位ではありません(ただし、秒単位など)。
ここで私がMS(MILLISECONDS)を取得するために使用するもの:
迅速:
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 );
Swift 4の場合、クラスにデリゲートとして追加します。
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!))")
}
}
}
クラスに追加:
class MyViewcontroller: UIViewController, TimingDelegate
次に、クラスに追加します。
var _TICK: Date?
何かの時間を計りたいときは、次のことから始めます。
TICK
最後に:
TOCK("Timing the XXX routine")