高分辨率计时器
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。
浙公网安备 33010602011771号