C++中常用的跨平台计时方案总结

计时是发掘系统中时间性能瓶颈的必不可少的一环。

由于C++语言存在各种不同的实现版本,可选用的计时方案也比较多,本文介绍了各种常用的跨平台计时方案,包括:

  • C计时方案clock
  • C计时方案time
  • STL计时方案std::chrono::clocks
  • QT计时方案QTime
  • Boost计时方案timer

而对于平台依赖的方案,不在本文的介绍范围之内,比如:Windows平台下的GetTickCountQueryPerformanceCounter,*inux平台下的hrtimergettimeofday
本文以task()函数为例来说明各计时方案用法,在之后的代码中,就不再定义了:

void task()
{
    static int value = 0;
    while(0 <= value++);
}

C计时方案clock

clock是C标准库中的函数,在time.h中声明,函数签名如下:

#include 

clock_t clock(void);

值得说明一下的是,clock返回的是处理器调用某个进程或函数所花费的时间,而不是系统时钟时间,也就是说,如果调用过程有sleep,不会计算在内。
此外,函数返回结果clock_t类型值需要除以CLOCKS_PER_SEC才能得到秒数值。而且对于不同平台,CLOCKS_PER_SEC的值也是不一样的,笔者知道的取值有10001000000
下面代码说明用法:

#include 
#include 

void task();

int main()
{
    std::clock_t start = std::clock();
    task();
    std::clock_t end = std::clock();

    double duration = (end - start)/(double)CLOCKS_PER_SEC;
    std::cout << duration << std::endl;
}

C计时方案time

timeclock一样,也是在time.h中声明的C标准库函数,函数签名如下:

#include 

time_t time (time_t *__timer);

clock不同的是,time传入一个time_t*,然后返回系统时钟时间,而不是CPU时间。
其基本用法如下:

#include 
#include 

void task();

int main()
{
    std::time_t start, end;
    
    std::time(&start);
    task();
    std::time(&end);

    double duration = std::difftime(end, start);
    std::cout << duration << std::endl;
}

STL计时方案std::chrono::clocks

C++ 11提供了高精度时间的标准库chrono,其中抽象了三个概念:

  • 时间点:std::chrono::steady_clock::time_point
  • 时钟:std::chrono::clocks
  • 时间间隔:std::chrono::duration

std::chrono::clocks用来计时,实现的时钟有三个:

  • system_clock:系统时钟,与系统显示时间保持一致,可人为修改。
  • steady_clock:稳定时钟,不随系统时间变化,不可修改。
  • high_resolution_clock:高精度时间,目前存在移植性问题,暂不推荐使用。

由此可见,采用steady_clock最合适。
下面来看基本用法:

#include 
#include 

void task();

int main()
{
    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
    task();
    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

    std::chrono::milliseconds duration = 
            std::chrono::duration_cast(end - start);
    std::cout << duration.count() / 1000.0 << std::endl;
}

其中(end - start)需要利用duration_cast转换成需要的统计单位。

QT计时方案QTime

QT计时方案主要采用QTime这个类,用到函数:

  • QTime::start()方法用于启动计时器
  • QTime::restart()方法用于重启计时器
  • QTime::elapsed()方法返回计时器从启动(startrestart)到当前的毫秒数。

用法简单举例如下:

#include 
#include 

void task();

int main()
{
    QTime time;

    time.start();
    task();
    int duration = time.elapsed();

    std::cout << duration / 1000.0 << std::endl;
}

Boost计时方案timer

Boost是业界比较流行的C++库,其中用到的计时类boost::timer与QT非常相似:

  • 对象构造完成时,定时器启动
  • boost::timer::restart()重新启动定时器
  • boost::timer::elapsed()返回启动的时间,单位为秒

下面说明用法:

#include 
#include 

void task();

int main()
{
    boost::timer t;
    task();
    double duration = t.elapsed();

    std::cout << duration << std::endl;
}

总结

本文介绍了常用的跨平台计时方案,从功能角度考虑,clock返回CPU运行时间,而其余均返回时钟时间;从精度角度来看,std::chrono::clocks精度最高,达到纳秒级别;从接口的角度,QTimeboost::timer提供了专门的timer类,接口更加优雅,其余方案仅仅是对时钟的一种使用。
综合考虑,笔者会推荐std::chrono::clocks

名称 功能 精度 接口设计 通用性
clock CPU时间 毫秒/微秒 一般
time 时钟时间 毫秒/微秒 一般 一般
std::chrono::clocks 时钟时间 纳秒 一般
QTime 时钟时间 毫秒 一般
boost::timer 时钟时间 毫秒/微秒 一般

说在最后

计时 一般指代码块从开始到结束,系统运行的时间,也可能指CPU时间片的时间,是一个不太精确的数值。如果需要精确考虑某个线程运行时间或某个过程的系统时间和用户时间,则需要进一步考虑其他解决方案。

你可能感兴趣的:(C++中常用的跨平台计时方案总结)