ios 如何以毫秒为单位准确记录方法的执行时间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2129794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:49:28  来源:igfitidea点击:

How to log a method's execution time exactly in milliseconds?

iosobjective-coptimizationtime

提问by dan

Is there a way to determine how much time a method needs to execute (in milliseconds)?

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

回答by Matthew McGoogan

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:

斯威夫特3:

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.

易于使用且具有亚毫秒级精度。

回答by Ron

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;

回答by Stephen Canon

For fine-grained timing on OS X, you should use mach_absolute_time( )declared in <mach/mach_time.h>:

对于 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;

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 profileyour application running using a tool like Shark. This won't give you exact timing information, but it will tell you what percentageof the application's time is being spent where, which is often more useful (but not always).

此外,请注意,您可能会发现更多有用的配置文件运行的应用程序中使用像鲨鱼的工具。这不会为您提供准确的时间信息,但它会告诉您应用程序时间的百分比花在哪里,这通常更有用(但并非总是如此)。

回答by Alex Nazarsky

There is a convenient wrapper for mach_absolute_time()– it's a CACurrentMediaTime()function.

有一个方便的包装器mach_absolute_time()——它是一个CACurrentMediaTime()函数。

Unlike NSDateor CFAbsoluteTimeGetCurrent()offsets, mach_absolute_time()and CACurrentMediaTime()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.

不同于NSDateCFAbsoluteTimeGetCurrent()偏移, mach_absolute_time()并且CACurrentMediaTime()基于内部主机时钟,这是一种精确的单原子度量,不受外部时间参考的变化影响,例如由时区、夏令时或闰秒引起的变化。



ObjC

对象

CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);

Swift

迅速

let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")

回答by Adriano Spadoni

In Swift, I'm using:

在 Swift 中,我使用:

In my Macros.swift I just added

在我的 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)")
}

you can now just call anywhere

你现在可以在任何地方打电话

TICK()

// your code to be tracked

TOCK()
  • 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
  • 此代码基于 Ron 的代码转换为 Swift,他有功劳
  • 我在全球范围内使用开始日期,欢迎提出任何改进建议

回答by bladnman

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

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

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

再次,查看我的帖子了解更多信息或在此处下载: MMStopwatch.zip

回答by Sergey Teryokhin

I use macros based on Ron'ssolution.

我使用基于Ron解决方案的宏。

#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

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

回答by zubko

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
  • [DBGStopwatch start:@"slow-operation"];一开始就打电话
  • 然后[DBGStopwatch stop:@"slow-operation"];在完成后,得到时间

回答by FuzzyBunnySlippers

You can get reallyfine 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 类,您可以获得非常精确的计时(秒。秒的部分)。它使用 iPhone 中的高精度计时器。使用 NSDate 只会让你秒(s)精度。这个版本是专门为 autorelease 和 Objective-c 设计的。如果需要,我也有一个 C++ 版本。 您可以在此处找到 C++ 版本

StopWatch.h

秒表.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

秒表.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 stopWatchmethod that returns an autoreleased object.

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

Once you call start, use the secondsmethod to get the elapsed time. Call startagain to restart it. Or stopto stop it. You can still read the time (call seconds) anytime after calling stop.

调用后start,使用该seconds方法获取经过的时间。start再次调用以重新启动它。或者stop阻止它。您仍然可以在调用seconds后随时读取时间(调用)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]]];
}

回答by Mike Dunlavey

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 doyou need a different technique. This is what I recommend, and I know you can do it on iPhones.

好的,如果您的目标是找出可以修复的内容以使其更快,那是一个有点不同的目标。测量函数花费的时间是找出你所做的事情是否有所不同的好方法,但要找出要做什么,你需要一种不同的技术。这是我推荐的,我知道你可以在 iPhone 上做到这一点。

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 Nseconds.
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 mseconds.
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:

编辑:审稿人建议我详细说明答案,因此我正在尝试想出一种简短的表达方式。
您的整个程序需要足够的时钟时间来打扰您。假设那是N秒。
你假设你可以加快速度。你能做到这一点的唯一方法是让它不做它在那个时候正在做的事情,占m秒。
你一开始不知道那是什么东西。您可以像所有程序员一样猜测,但它很容易是别的东西。无论它是什么,您都可以通过以下方式找到它:

Since that thing, whatever it is, accounts for fraction m/Nof the time, that means if you pause it at random the probability is m/Nthat 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.

因为那件事,不管它是什么,占时间的分数m/N,这意味着如果你随机暂停它,你在做那件事时会抓住它的概率是m/N。当然,它可能正在做其他事情,但暂停一下,看看它在做什么。
现在再做一次。如果您再次看到它做同样的事情,您可能会更加怀疑。

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 exactlywhat to fix.
If you also want to know very exactlyhow 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.

做 10 次,或 20 次。现在如果你看到它在多次暂停中做一些特定的事情(无论你如何描述它),你可以摆脱,你知道两件事。您非常粗略地知道需要多少时间,但您非常确切地知道要修复什么。
如果您还想非常准确地知道将节省多少时间,那很容易。之前测量,修复它,然后测量它。如果您真的很失望,请退出修复程序。

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.

你看到这与测量有何不同吗?它是发现,而不是测量。大多数分析都是基于尽可能准确地测量花费了多少时间,好像这很重要,并且手动挥手确定需要修复的问题。分析并不能找到所有问题,但这种方法确实可以找到所有问题,而且正是您没有发现的问题会伤害您。