zoukankan      html  css  js  c++  java
  • C++高精度计时器——微秒级时间统计

    在C++中,经常需要通过计时来统计性能信息,通过统计的耗时信息,来分析性能瓶颈,通常情况下,可能毫秒级别的时间统计就足够用了,但是在毫厘必争的性能热点的地方,毫秒级别的统计还是不够的,这种情况下,就需要至少微秒级别的统计信息,甚至要精确到CPU的指令周期级别。下面来重点说一下毫秒级的计时统计信息。

    毫厘必争--微秒计时思路

    在Windows平台上,用来统计微秒级别耗时信息,需要用到两个Windows API:

    BOOL WINAPI QueryPerformanceFrequency(
      _Out_  LARGE_INTEGER *lpFrequency
    );
    
    BOOL WINAPI QueryPerformanceCounter(
      _Out_  LARGE_INTEGER *lpPerformanceCount
    );

    QueryPerformanceFrequency用于获取性能计数的频率,每秒多少次,

    QueryPerformanceCounter用于获取当前性能计数的值,

    有了这两个API,我们就可以用来统计耗时了,思路如下:

    统计耗时

    那么如何得到最终的耗时呢,相信不难回答,公式如下:

    秒级耗时 = (结束性能计数值 - 开始性能计数值) / 性能计数频率
    
    微秒耗时 = (结束性能计数值 - 开始性能计数值)* 1000000 / 性能计数频率

    微秒计时实现

    LARGE_INTEGER freq_;
    QueryPerformanceFrequency(&freq_);
    
    LARGE_INTEGER begin_time;
    LARGE_INTEGER end_time;
    QueryPerformanceCounter(&begin_time);
    Sleep(100);
    QueryPerformanceCounter(&end_time);
    
    double ns_time = (end_time.QuadPart - begin_time.QuadPart) * 1000000.0 / freq_.QuadPart;

    封装微秒计时的实现

    虽然上面已经实现了微秒精度计时,但是由于每次调用API时,都要定义变量等,使用起来肯定会有很多重复或者类似的代码,那么为了避免这种情况,对此实现进行了封装,如下:

    class stop_watch
    {
    public:
        stop_watch()
            : elapsed_(0)
        {
            QueryPerformanceFrequency(&freq_);
        }
        ~stop_watch(){}
    public:
        void start()
        {
            QueryPerformanceCounter(&begin_time_);
        }
        void stop()
        {
            LARGE_INTEGER end_time;
            QueryPerformanceCounter(&end_time);
            elapsed_ += (end_time.QuadPart - begin_time_.QuadPart) * 1000000 / freq_.QuadPart;
        }
        void restart()
        {
            elapsed_ = 0;
            start();
        }
        //微秒
        double elapsed()
        {
            return static_cast<double>(elapsed_);
        }
        //毫秒
        double elapsed_ms()
        {
            return elapsed_ / 1000.0;
        }
        //
        double elapsed_second()
        {
            return elapsed_ / 1000000.0;
        }
    
    private:
        LARGE_INTEGER freq_;
        LARGE_INTEGER begin_time_;
        long long elapsed_;
    };

    那么,如何使用此封装的类呢,来看一下调用的例子:

    stop_watch watch;
    watch.start();
    Sleep(100);
    watch.stop();
    cout << watch.elapsed() << " ns" << endl;

    看看调用是不是更方便了呢,是不是有点似曾相识的感觉,对,没错,你猜对了。。。

    参考资料

    QueryPerformanceFrequency

    QueryPerformanceCounter

  • 相关阅读:
    利用栈计算后缀式
    中缀式转换为后缀式(逆波兰式)方法
    JAVA字符串首字母大小写转换(截取转换+移动ASCII编码)
    VSCode格式化代码后,设置代码不自动换行
    oracle连接不上,提示监听服务不可用的解决办法
    壹周立波秀
    欣慰,举手之力,帮助一个老同学恢复了博士论文文档
    开发中的思维转换也是一种创新-思维创新
    电脑借液晶电视显示器出现雪花点的另类解决办法
    邮箱已满解决办法
  • 原文地址:https://www.cnblogs.com/hbccdf/p/microsecond_performance_statistics.html
Copyright © 2011-2022 走看看