【问题标题】:Microbenchmark in iOS - Time how long a method takes to executeiOS 中的微基准测试 - 方法执行所需的时间
【发布时间】:2016-09-04 08:53:43
【问题描述】:

我正在尝试查看为 iOS 版本 7-8-9 编译的应用程序在 Xcode 7 中执行方法需要多长时间。

看到这个问题,Getting the time elapsed (Objective-c)。答案警告不要依赖 NSDate 如此短暂的时间。取而代之的是this Answer 建议:

CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;

即使在导入#import <QuartzCore/QuartzCore.h> 之后,此代码也无法编译。报告链接器故障:

架构 armv7 的未定义符号:

“_CACurrentMediaTime”,引用自:

还有其他方法可以以毫秒或纳秒为单位跟踪短暂的时刻吗?

请不要警告使微基准测试不可靠的内在变幻莫测。我只是想对时间有一个粗略的概念。

也许 Objective-C 或 Swift 有类似于 JMH, Java Micro-benchmarking Harness 的东西,用于构建、运行和分析用 Java 和其他针对 Java Virtual Machine 的语言编写的 nano/micro/milli/macro 基准测试。

【问题讨论】:

  • 我觉得xcode单元测试有性能测试的方法。不确定您是否可以以纳秒为单位查看时间。可能多次调用该方法然后除以总时间?
  • @Surely 谢谢,但我不是单元测试。我只想捕获开始和停止时间来计算单个方法顶部和底部附近的经过时间。
  • 问题不只是缺乏精确性;乱序执行会使结果变得更糟,而不仅仅是嘈杂。例如结束时间可以在您尝试测量的代码的结果仍在等待缓存未命中时进行采样,或者甚至是在缓存中将全部丢失的短链相关负载。当然,这通常只是不需要系统调用的时间源的问题(如 x86 的 RDTSC 指令,并且不(单独)序列化乱序执行。)使系统调用序列化大多数 CPU 设计中的流水线。

标签: ios objective-c benchmarking microbenchmark


【解决方案1】:

NSDate

其他人警告说,NSDate 在用于微基准测试时可能会有些晃动。但对于随意使用,它工作得很好。

NSDate *start = [NSDate date];
// …
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
NSLog(@"elapsedTime after Check call: %f" , timeInterval );

可能有更好的方法,但这确实有效。例如,我对第 5 代 iPod touch 上的方法调用进行了计时,在几次运行中它始终需要 0.21 到 0.25 秒。在多次运行中,以相同的方法切换到 iPad Air 始终需要 0.11 到 0.13 秒。当然,这在两种设备上大约有 10-20% 的差异。不过随便观察一下,这可能就满足你的需要了。只需确保多次运行测试即可。

使用 Receigen 代码运行示例

示例运行,执行一些代码,这些代码利用Receigen Mac 应用为App Receipt Validation 生成的源代码。 NSDate 似乎可以很好地跟踪微秒。

我不包括源代码,但是您可以通过对事件顺序的描述了解主要思想。

  • 定义并填充了block of code。没有执行任何业务逻辑,只是创建了Objective-C blockclosure)。
  • 我的SKRequestDelegate 实现被实例化了。没有真正的代码,只是通过 NSLog 进行一些日志记录。
  • 执行生成的 Receigen 代码。这是一组经过混淆的 C 代码,通过调用 OpenSSL 解析 Apple 的 App Receipt 来完成一些解密工作。
  • 在解密和解析之后,Receigen 通过调用我们在顶部定义的块来报告其结果。对于我们的三个应用内购买产品中的每一个,都会调用一次此块。
  • 在 Receigen 生成的代码返回后,最后一次捕获经过的时间。

您可以在下面看到块定义只有 22 微秒。 SKRequestDelegate 的实例化要多得多,大约 1,500 微秒。 Receigen 解密和解析花费了绝大多数时间,大约 0.1 秒来执行。然后大约 100 微秒,通过每次调用块 3 次来报告其发现。

2016-09-03 17:13:57.883 XXApp[231:7509] 声明和填充块后经过的时间:-0.000022

2016-09-03 17:13:57.884 XXApp[231:7509] 实例化实现SKRequestDelegate 后经过的时间:-0.001579

2016-09-03 17:13:57.995 XXApp[231:7509] 在 Receigen 代码调用块后经过的时间:-0.112392

2016-09-03 17:13:57.995 XXApp[231:7509] elapsedTime 后接收代码调用块:-0.112482

2016-09-03 17:13:57.995 XXApp[231:7509] 在 Receigen 代码调用块后经过的时间:-0.112556

2016-09-03 17:13:57.997 XXApp[231:7509] elapsedTime after Receigen code done: -0.115133

在运行了几次并获得一致的结果后,我得出结论,NSDate 对于毫秒-微秒范围内的随意基准测试确实很有用。

【讨论】:

  • 十分之一秒几乎可以肯定。当人们谈论对单个动作进行微基准测试时,通常是在数百到数千个时钟周期内,其中时钟精度和测量开销,甚至 CPU 采样时钟的无序执行都是巨大的因素。你离这些问题大约有 4 个数量级。除非 NSDate 真的不精确,否则结果中的噪声不是测量伪影,可能是真实的(即您的过程确实需要可变的时间)。缓存未命中、中断或其他因素的变化。
猜你喜欢
  • 2011-02-20
  • 1970-01-01
  • 2011-02-02
  • 2023-04-07
  • 1970-01-01
  • 2015-01-07
  • 1970-01-01
  • 2023-03-25
  • 2012-07-09
相关资源
最近更新 更多