【问题标题】:High-resolution timer for iPhone?iPhone的高分辨率计时器?
【发布时间】:2011-04-02 04:46:41
【问题描述】:

我正在寻找 iPhone 的高分辨率计时代码,以便进行一些性能计时。我想写这样的代码:

HighResolutionTimer* myTimer = [[HighResolutionTimer alloc]init];
[myTimer start];
[self doSomeLengthyOperation];
NSLog( @"doSomeLengthyOperation took %f seconds", [myTimer elapsedTime] );

【问题讨论】:

  • 为什么不直接使用getrusage()?在 C 中工作的任何东西都将在 Objective-C 中工作。
  • 因为有一个非常好的 Cocoa 方法可以做同样的事情。

标签: iphone objective-c timer high-resolution


【解决方案1】:

查看 mach/mach_time.h 标头中的 mach_absolute_time()。

不要使用 NSDate。当 ntp 做它的事情时,NSDate 甚至不能保证偶尔不会倒退。

(设备可能会有时钟漂移。如果 iOS 设备快速漂移几秒钟,那么当 NTP 纠正这种漂移时,你会看到时钟突然倒退几秒钟。非常不适合计时使用。mach_time 使用一个计数器NTP永远不会纠正,因此不能倒退,因此更适合计时。)

【讨论】:

  • NSDate 只返回一个计算自 2001 年 1 月 1 日以来秒数的双精度数。对于秒表计时,不会出现负时间,所以我认为不需要带来 mach_absolute_time() 的开销进入你的代码——both implemented here.
  • @bobobobo :自 2001 年 1 月 1 日以来设备的秒数偶尔会被 NTP 向后更正。因此,在具有有时会快速漂移的时钟晶体以及可以纠正这种漂移的网络连接的任何给定设备上,它都可以是非单调的。
  • 我最终使用了 mach_absolute_time()。我发现了一个使用它的小类,here
  • @howpaw2 这是一个非常好的观点,您应该将漂移时钟的解释纳入您的答案。实际上,我可以看到这是一个非常奇怪的错误,开发人员很难找到甚至重复。
【解决方案2】:

更好的选择是CACurrentMediaTime(),它使用mach_absolute_time(),但为您将其转换为CFTimeInterval(即,以秒为单位的时间)。

【讨论】:

【解决方案3】:

这是我对使用mach_absolute_time() 的时钟计时器的回答,基于计算方法shown hereNSDate。就准确度而言,它们实际上是相同的。

马赫版本

double machGetClockS()
{
  static bool init = 0 ;
  static mach_timebase_info_data_t tbInfo ;
  static double conversionFactor ;
  if(!init)
  {
    init = 1 ;
    // get the time base
    mach_timebase_info( &tbInfo ) ;
    conversionFactor = tbInfo.numer / (1e9*tbInfo.denom) ; // ns->s
  }

  return mach_absolute_time() * conversionFactor ; // seconds
}

double machGetClockDiffS()
{
  static double lastTime = 0;

  double currentTime = machGetClockS() ;

  double diff = currentTime - lastTime ;

  lastTime = currentTime ; // update for next call

  return diff ; // that's your answer
}

NSTimeInterval 版本

double getClockS()
{
  return [NSDate timeIntervalSinceReferenceDate] ; // NSTimeInterval is always specified in seconds 
}

double getClockDiffS()
{
  static double lastTime = 0 ;

  double currentTime = getClockS() ;

  double diff = currentTime - lastTime ;

  lastTime = currentTime ; // update for next call

  return diff ; // that's your answer
}

结果:

请注意,这两者的分辨率都非常好。

IOS SIMULATOR,运行帧率计数(以毫秒为单位 (*1000.0)) MACH_ABS_TIME / NSTimeIntervals 58.557001 / 58.552980 40.558007 / 40.562987 52.207822 / 52.200019 33.742197 / 33.742011 38.498912 / 38.504004 48.872679 / 48.868001 45.012602 / 45.011997 57.858432 / 57.865977 25.044615 / 25.038004 IPAD 硬件样品: 33.415041 / 33.416033 33.240167 / 33.239007 33.357542 / 33.357978 33.302833 / 33.302009 33.506750 / 33.509016 33.582250 / 33.582985 33.233958 / 33.232987 33.239042 / 33.237994

*如果你查看这篇帖子的编辑历史,你会发现使用float 代替double 的危险!

【讨论】:

  • 你忘了添加 init = true;在 machGetClockS() 中。
  • 不是一个很好的时间分辨率测试,因为您在没有使用 Wireshark 监控的情况下测试任何 NTP 网络连接,这有时真的会干扰 NSDate 结果。
【解决方案4】:

使用NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate] 获取开始时间,然后在结束时使用NSLog (@"Operation took %f seconds.", [NSDate timeIntervalSinceReferenceDate] - startTime);

【讨论】:

  • 效果很好,谢谢!我没有意识到 NSDate 有这种精确度。
猜你喜欢
  • 1970-01-01
  • 2011-10-31
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
相关资源
最近更新 更多