• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

-陌陌-

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

高分辨率计时器

详细介绍计时器的实现过程: 1. C clock()的弊端 2. Windows平台QueryPerformanceCounter()的用法 3. Unix类平台的gettimeofday()的用法 4. 给出封装的Timer类

C标准库提供clock()函数,它可以用于计算经过的时间。它是定义在time.h(ctime)中的一个操作系统独立的C函数(兼容于大多数操作系统),不过,它并不提供精确结果,甚至不提供毫秒级精度。

为了检测clock()的精度,在你的系统上尝试下列代码。输出结果显示clock()函数可以检测的最小时钟。

#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    clock_t t1, t2;
    t1 = t2 = clock();

    // 循环直到t2获取不同值
    while(t1 == t2)
        t2 = clock();

    // 打印clock()分辨率
    cout << (double)(t2 - t1) / CLOCKS_PER_SEC * 1000 << " ms.\n";

    return 0;
}

因此,我们需要至少1毫米的高分辨率计时器以测量过去时间。值得庆幸的是存在这样的高分辨率计时器函数,不过它们是系统特有的。也就是说,在不同系统,你需要书写不同的代码。Windows提供QueryPerformanceCounter()函数,Unix、Linux与Mac OS X系统拥有定义在sys/time.h中的gettimeofday()。这两个函数都能够测量至少1微秒的区别。

Windows

Windows API提供额外的高分辨率计时器函数,QueryPerformanceCounter()与QueryPerformanceFrequency()。QueryPerformanceCounter()用于获取当前过去的时钟计数,QueryPerformanceFrequency()用于获取每秒钟的时钟记数,它用于将时钟计数转换为实际时间。

下面为使用QueryPerformanceCounter()测量过去时间的用法。

#include <iostream>
#include <windows.h>                // 使用Windows APIs
using namespace std;

int main()
{
    LARGE_INTEGER frequency;        // 1秒的时钟标记
    LARGE_INTEGER t1, t2;               // 时钟计数
    double elapsedTime;

    // 获取每秒的时钟计数
    QueryPerformanceFrequency(&frequency);

    // 开始计时
    QueryPerformanceCounter(&t1);

    // 处理...
    ...

    // 结束计时
    QueryPerformanceCounter(&t2);

    // 计算与打印毫米级的过去时间
    elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
    cout << elapsedTime << " ms.\n";

    return 0;
}

Unix、Linux与Mac

gettimeofday()可以用于Unix或Linux类系统。该函数定义于”sys/time.h“,因此,在使用gettimeofday()之前必须包含该头文件。它也可以产生1微妙级的分辨率。这里为代码片段。

#include <iostream>
#include <sys/time.h>                // 使用gettimeofday()
using namespace std;

int main()
{
    timeval t1, t2;
    double elapsedTime;

    // 开始计时
    gettimeofday(&t1, NULL);

    // 处理...
    ...

    // 结束计时
    gettimeofday(&t2, NULL);

    // 计算以及打印毫秒级过去时间
    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;         // sec to ms
    elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;    // us to ms
    cout << elapsedTime << " ms.\n";

    return 0;
}

C++Timer类

该时钟类结合QueryPerformanceCounter()与gettimeofday()。因此,它可以用于Unix/Linux/Mac及Windows系统。它也提供简单的获取过去时间的借口。

头文件:

#ifdef WIN32   // Windows系统
#include <windows.h>
#else              // Unix类系统
#include <sys/time.h>
#endif


class Timer
{
public:
    Timer();
    ~Timer();

    void   start();                             // 开始计时
    void   stop();                              // 结束计时
    double getElapsedTime();                    // 获取秒级过去时间
    double getElapsedTimeInSec();               // 获取秒级过去时间(同getElapsedTime)
    double getElapsedTimeInMilliSec();          // 获取毫秒级过去时间
    double getElapsedTimeInMicroSec();          // 获取微妙级过去时间


protected:


private:
    double startTimeInMicroSec;
    double endTimeInMicroSec;
    int    stopped;
#ifdef WIN32
    LARGE_INTEGER frequency; 
    LARGE_INTEGER startCount; 
    LARGE_INTEGER endCount; 
#else
    timeval startCount; 
    timeval endCount; 
#endif
};

实现文件:

#include "Timer.h"
#include <stdlib.h>

Timer::Timer()
{
#ifdef WIN32
    QueryPerformanceFrequency(&frequency);
    startCount.QuadPart = 0;
    endCount.QuadPart = 0;
#else
    startCount.tv_sec = startCount.tv_usec = 0;
    endCount.tv_sec = endCount.tv_usec = 0;
#endif

    stopped = 0;
    startTimeInMicroSec = 0;
    endTimeInMicroSec = 0;
}

Timer::~Timer()
{
}

void Timer::start()
{
    stopped = 0; // 重置结束标记
#ifdef WIN32
    QueryPerformanceCounter(&startCount);
#else
    gettimeofday(&startCount, NULL);
#endif
}

void Timer::stop()
{
    stopped = 1; // 设置计时器结束标记

#ifdef WIN32
    QueryPerformanceCounter(&endCount);
#else
    gettimeofday(&endCount, NULL);
#endif
}

double Timer::getElapsedTimeInMicroSec()
{
#ifdef WIN32
    if(!stopped)
        QueryPerformanceCounter(&endCount);

    startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);
    endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
#else
    if(!stopped)
        gettimeofday(&endCount, NULL);

    startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;
    endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
#endif

    return endTimeInMicroSec - startTimeInMicroSec;
}

double Timer::getElapsedTimeInMilliSec()
{
    return this->getElapsedTimeInMicroSec() * 0.001;
}

double Timer::getElapsedTimeInSec()
{
    return this->getElapsedTimeInMicroSec() * 0.000001;
}

double Timer::getElapsedTime()
{
    return this->getElapsedTimeInSec();
}

下面代码展示基础用法。

#include <iostream>
#include "Timer.h"
using namespace std;

int main()
{
    Timer timer;

    // 开始计时
    timer.start();

    // 处理...
    ...

    // 结束计时
    timer.stop();

    // 打印毫秒级过去时间
    cout << timer.getElapsedTimeInMilliSec() << " ms.\n";

    return 0;
}

源代码在:timer.zip。

 

英文原文:http://www.songho.ca/misc/timer/timer.html

学习与分享

posted on 2014-08-20 23:01  -陌陌-  阅读(962)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3