【问题标题】:Rudimentary ways to measure execution time of a method测量方法执行时间的基本方法
【发布时间】:2023-04-07 18:13:01
【问题描述】:

我会调用什么对象/方法来获取以毫秒为单位的当前时间(或高精度),以帮助测量方法执行所需的时间?

NSDate 的 timeIntervalSinceDate 将返回以秒为单位的 NSInterval。我正在寻找更细粒度的东西,类似于 Java 的 System.currentTimeMillis。

objective-c/CocoaTouch 中是否有等效版本?

【问题讨论】:

  • 我在我的代码中使用一些快速而肮脏的计时的原因是因为我想缩小一个似乎有问题的区域,并且在我运行后我没有任何运气获得太多信息仪器和鲨鱼。所以为了避免被卡住,我选择了这条路线。
  • dispatch_benchmark() 是一种方式:nshipster.com/benchmarking

标签: objective-c


【解决方案1】:

对于 OS X 上非常细粒度的时序,我使用mach_absolute_time( ),它在<mach/mach_time.h> 中定义。您可以按如下方式使用它:

#include <mach/mach_time.h>
#include <stdint.h>

static double ticksToNanoseconds = 0.0;

uint64_t startTime = mach_absolute_time( );
// Do some stuff you want to time here
uint64_t endTime = mach_absolute_time( );

 // Elapsed time in mach time units
uint64_t elapsedTime = endTime - startTime;

// The first time we get here, ask the system
// how to convert mach time units to nanoseconds
if (0.0 == ticksToNanoseconds) {
    mach_timebase_info_data_t timebase;
    // to be completely pedantic, check the return code of this next call.
    mach_timebase_info(&timebase);
    ticksToNanoseconds = (double)timebase.numer / timebase.denom;
}

double elapsedTimeInNanoseconds = elapsedTime * ticksToNanoseconds;

【讨论】:

    【解决方案2】:

    实际上,+[NSDate timeIntervalSinceReferenceDate] 返回一个NSTimeInterval,这是一个双精度类型定义。文档说

    NSTimeInterval 总是以秒为单位指定;它在 10,000 年的范围内产生亚毫秒级的精度。

    因此可以安全地用于毫秒精度的计时。我一直这样做。

    【讨论】:

    • 您只需调用timeIntervalSinceReferenceDate 就会浪费很多时间,这会以不可预测的方式影响结果。
    • 投反对票是因为 - 实验性地 - 正如@GeorgSchölly 所说,Apple 已将 NSDate 实现为非常慢(至少在 iOS 上)。它几乎没用——他们的“timeInterval*”方法调用实际上在 Instruments 中显示为一个项目中最大的 CPU 占用!
    • 我在 iOS 上使用基于 NSDate(特别是 MGBenchmark)的解决方案的经验是,在单独测试循环中的每一行时,我发现它们之间几乎没有明显的区别。 Mach_time 不仅揭示了更准确的结果,而且还让消耗性能的代码行真正脱颖而出。
    【解决方案3】:

    不要为此使用NSDate 您在调用方法和实例化对象时会失去很多精度,甚至可能会释放内部的东西。你只是没有足够的控制权。

    使用time.hStephen Canon 建议的mach/mach_time.h。它们都更准确。

    最好的方法是启动 Instruments 或 Shark,将它们附加到您的进程(即使它已经在运行也可以工作)并让它们测量一个方法所花费的时间。

    在您熟悉它之后,这比任何投入马赫时间功能和重新编译整个应用程序的解决方案所花费的时间都更少。你甚至可以获得很多额外的信息。我不会满足于任何更少的东西。

    【讨论】:

    • 注意:有些用例中 Instruments 是无用的。例如一个 OpenGL 应用程序 - 我需要知道哪些着色器运行得快与慢,以及哪些后台方法占用了多少时间……在最终用户的设备上。在某些情况下,我想动态切换到不同的渲染路径。不能要求他们运行 Instruments ;),这无论如何都会阻止运行时更改,所以 ... time/mach_time 很好。
    【解决方案4】:

    timeIntervalSinceReferenceDate 完全没问题。

    但是,除非它是一种长期运行的方法,否则不会产生太大的效果。当您谈论几毫秒的执行时,执行时间可能会有很大差异。如果您的线程/进程在中途被抢占,您将遇到不确定的尖峰。本质上,您的样本量太小。使用分析器或运行 100,000 次迭代以获得总时间并除以 100,000 以获得平均运行时间。

    【讨论】:

      【解决方案5】:

      如果您正在尝试调整代码的性能,最好使用 Instruments 或 Shark 来全面了解您的应用在哪里花费时间。

      【讨论】:

        【解决方案6】:

        我将在此处从另一篇文章中重新发布我的答案。请注意,对于这个复杂问题,我公认的简单解决方案使用 NSDate 和 NSTimeInterval 作为其基础:


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

        最好的办法是查看我的博客文章: Timing things in Objective-C: A stopwatch

        基本上,我写了一个以非常基本的方式停止观看但被封装的类,因此您只需要执行以下操作:

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

        你最终得到:

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

        在日志中...

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

        【讨论】:

        • 如上所述:你不应该使用 NSDate。此外,这个答案确实没有增加任何东西,它只是以额外的间接方式重新包装现有(损坏的)方法,这无济于事
        • 我在此不敢苟同。 NSDate 适用于某些操作。正如我所说,这是一个非常困难的问题的简单解决方案。我同意所选答案的准确性肯定是更好的选择。也就是说,我仍然喜欢使用 2 行快速代码来了解我的程序中的时间。
        【解决方案7】:

        @bladnman 我喜欢你的秒表。我一直在使用它。这是我写的一个小块,它消除了结束通话的需要,并使它更容易(如果这看起来可能的话)使用,哈哈。

        +(void)stopwatch:(NSString*)name timing:(void(^)())block {
            [MMStopwatch start:name];
            block();
            [MMStopwatch stop: name];
        }
        

        那么你可以在任何地方调用它..

        [MMStopwatch stopwatch:@"slowAssFunction" timing:^{
            NSLog(@"%@",@"someLongAssFunction");
        }]; 
        

        someLongAssFunction

        -> Stopwatch: [slowAssFunction] runtime:[0.054435]
        

        您应该将那个傻瓜发布到 github - 这样人们就可以轻松找到它/做出贡献等。这很棒。谢谢。

        【讨论】:

        • 太棒了!我喜欢。在一个块中使用它是有意义的。很酷。
        猜你喜欢
        • 2012-05-14
        • 2011-09-08
        • 1970-01-01
        • 2020-11-28
        • 1970-01-01
        • 2012-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多