mach_absolute_time 高效计算时间差

mach_absolute_time 使用

  今天看荣哥时间常用函数封装里有个不常见的函数 ,mach_absolute_time() ,经查询后感觉是个不错的函数,网上关于这个函数搜索以后简单整理来一下。

什么事Mach? 

时间例程依赖于所需要测量的时间域。 某些情况下使用诸如clock() 或 getrusage()函数来做简单的数学运算就足够了。如果时间例程将用于实际开发框架之外,可移植性就很重要来。

 mach_absolute_time  是一个CPU/总线依赖函数,返回一个基于系统启动后的时钟"嘀嗒"数。在macOS上可以确保它的行为,并且,它包含系统时钟所包含的所有时间区域。其可获取纳秒级的精度。

使用mac_absolute_time时需要考虑两个因素:

1.如何获取当前的Mach绝对时间。

2.如何将其转换为有意义的数字。

* 获取mach_absolute_time非常简单

#include <stdint.h>

uint64_t start = mach_absolute_time();//是纳秒
uint64_t stop = mach_absolute_time();

这样我们就可以得到两个值,即可获得两个时间的时间差。

* 讲mach_absolute_time时间差转换为秒数,这稍微复杂点了,因为我们需要获得mach_absolute_time所基于的系统时间基准。

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

double subtractTimes(uint64_t endTime,uint64_t startTime)
{
  uint64_t difference = endTime - startTime;
  static double conversion = 0.0;
  if(conversion == 0.0)
  {
     mach_timebase_info_data_t info;
    kern_return_t err = mach_timebase_info(&info);

  //convert the timebase into seconds
  if(err ==0)
   {
      conversion = 1e-9 * (double) info.numer / (double)info.denom;  
  }        
  return conversion * (double)difference;
}

这里最重要的是调用mach_timebase_info. 我们传递一个结构体以返回时间基准值。最后,一旦我们获取到了系统的时间心跳,我们便能够生成一个转换因子。通常,转换是通过分子(info.numer)除以分母(info.denom).这里乘以一个1e-9来获取秒数。最后,我们获取两个时间的差值,并乘以转换因子,便得到真实的时间差。

网速找的一个比较好的例子:

1

2

3

4

5

#import <mach/mach_time.h>

double machTimeToSecs(uint64_t time)

{

  mach_timebase_info_data_t timebase;<br>  mach_timebase_info(&timebase);<br>  return(double)time *(double)timebase.number / (double)timebase.denom / 1e9;<br>}<br><br>-(void)profileDoSometing<br>{<br>  uint64_t begin = mach_absolute_time();<br>  [self dosomething];<br>  uint64_t end = mach_absolute_time();<br>  NSLog(@"Time taken to doSomething %g s",machTimeToSecs(end - begin));<br>}<br><br>-(void)dosomething<br>{<br>  for(int i = 0;i < 10000;i++){<br><br>    NSLog(@"test");<br>  }<br>}<br><br>    <br>

  

荣哥封装的是这样的:

+ (uint64_t)getStartTime
{
    uint64_t nStartTick = mach_absolute_time();// 单位事纳秒
    return nStartTick;
}

+ (double)getDurationSecondTime:(uint64_t)nStartTick
{
    uint64_t nTotalTick = mach_absolute_time()-nStartTick;
    double fTotalSecond = [self machTimeToSecs: nTotalTick];
    return fTotalSecond;
}

+ (double)machTimeToSecs:(uint64_t)time
{
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    return (double)time*(double)timebase.numer/(double)timebase.denom/1e9;//ns 转换为 s
}

使用时候,直接调用getStartTime开始计时,调用getDurationSecondTime获得结束时间

网上还有一个通过该函数测某方法运行时间,以便代码优化,感觉也是不错的,记录下来以便备用。

#import <Foundation/Foundation.h>
#import "TimeOperations.h"

#define LOOPAGE 10000000

CGFloat BNRTimeBlock (void (^block)(void)) {
    mach_timebase_info_data_t info;
    if (mach_timebase_info(&info) != KERN_SUCCESS) return -1.0;
    
    uint64_t start = mach_absolute_time ();
    block ();
    uint64_t end = mach_absolute_time ();
    uint64_t elapsed = end - start;
    
    uint64_t nanos = elapsed * info.numer / info.denom;
    return (CGFloat)nanos / NSEC_PER_SEC;
    
} // BNRTimeBlock

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        CGFloat time;
        
        NSString *thing1 = @"hi";
        NSString *thing2 = @"hello there";
        
        time = BNRTimeBlock(^{
            for (int i = 0; i < LOOPAGE; i++) {
                [thing1 isEqual: thing2];
            }
        });
        printf ("isEqual: time: %f\n", time);
        
        time = BNRTimeBlock(^{
            for (int i = 0; i < LOOPAGE; i++) {
                [thing1 isEqualToString: thing2];
            }
        });
        printf ("isEqualToString: time: %f\n", time);

        
    }
    return 0;
}
CGFloat ComputeTimeBlock (void (^block)(void)) {
    mach_timebase_info_data_t info;
    if (mach_timebase_info(&info) != KERN_SUCCESS) return -1.0;
    
    uint64_t start = mach_absolute_time ();
    block ();
    uint64_t end = mach_absolute_time (); // 此时是纳秒
    uint64_t elapsed = end - start;
    
    uint64_t nanos = elapsed * info.numer / info.denom;
    CGFloat test =  (CGFloat)nanos / NSEC_PER_SEC;
    return test;
}

CGFloat ComputeTimeBlock2 (void (^block)(void)) {
    mach_timebase_info_data_t info;
    if (mach_timebase_info(&info) != KERN_SUCCESS) return -1.0;
    
    uint64_t start = CACurrentMediaTime(); // 此时是秒
    block ();
    uint64_t end = CACurrentMediaTime();
    uint64_t elapsed = end - start;
    
    return elapsed;
}

从〇开始,回到〇

发布了29 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43778179/article/details/104573760