在Mac OS上测量毫秒的最佳方法是什么?

3

我找到了一个功能,可以获取自Mac启动以来的毫秒数:

U32 Platform::getRealMilliseconds()
{
   // Duration is a S32 value.
   // if negative, it is in microseconds.
   // if positive, it is in milliseconds.
   Duration durTime = AbsoluteToDuration(UpTime());
   U32 ret;
   if( durTime < 0 )
      ret = durTime / -1000;
   else 
      ret = durTime;

   return ret;
}

问题在于,经过约20天后AbsoluteToDuration一直返回INT_MAX,直到Mac重新启动。
我尝试使用下面的方法,它能够解决问题,但是看起来gettimeofday需要更多的时间来减缓游戏速度。
timeval tim;
gettimeofday(&tim, NULL);
U32 ret = ((tim.tv_sec) * 1000 + tim.tv_usec/1000.0) + 0.5;

有没有更好的方法来获取自某个时刻以来的毫秒数(最好是自应用程序启动以来)?

谢谢!


你可以将 int 改为 unsigned int 或 unsigned __int64。 - pyCthon
2个回答

4

我推荐的方法是使用mach_absolute_time - 参见此技术说明。 我使用第二种方法,即使用mach_absolute_time获取时间戳,再用mach_timebase_info获取转换时间戳之间差值所需的常数,从而将差值转换为实际时间值(具有纳秒分辨率)。


我认为这并没有被记录下来,但我曾经被一位苹果工程师告知UpTime只是对mach_absolute_time的一个薄包装。 - JWWalker
@JWWalker:是的,我认为那可能是正确的 - 而且我认为所有时间函数(或至少是CoreServices中的那些)最终都基于mach_absolute_time。我使用最低级别的API来获取收集时间戳时的最小开销。 - Paul R

4
您的实际问题是,您正在尝试将以毫秒为单位的正常运行时间转换成32位整数。如果这样做,无论如何获得该值,49天或更短的时间后,您的值都将始终回到零(或饱和)。
一种可能的解决方案是使用64位整数跟踪时间值;这样,灾难日就会被推迟几百年,所以您不必担心这个问题。下面是MacOS/X的实现方式:
uint64_t GetTimeInMillisecondsSinceBoot()
{
   return UnsignedWideToUInt64(AbsoluteToNanoseconds(UpTime()))/1000000;
}

如果您不想返回64位时间值,那么下一个最好的选择就是在程序启动时记录当前的毫秒级时间值,然后始终从返回的值中减去该值。这样,除非您的程序已经运行了至少49天,否则不会出现问题,我想这对于游戏来说是不太可能的。

uint32_t GetTimeInMillisecondsSinceProgramStart()
{
   static uint64_t _firstTimeMillis = GetTimeInMillisecondsSinceBoot();
   uint64_t nowMillis = GetTimeInMillisecondsSinceBoot();
   return (uint32_t) (nowMillis-_firstTimeMillis);
}

非常感谢!主要问题在于AbsoluteToDuration没有溢出,而是停留在MAX_INT上,导致所有时间都为0。您的解决方案解决了这个问题。 - k3a
1
你的 GetTimeInMillisecondsSinceBoot 函数体也可以写成 return UnsignedWideToUInt64( AbsoluteToNanoseconds( UpTime() ) ) / 1000000; - JWWalker
@JWWalker同意,那样做更好。我已经更新了我的答案,谢谢! - Jeremy Friesner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接