如何使用QueryPerformanceCounter?
我最近决定,我需要改变从毫秒到微秒为我的计时器类,经过一些研究,我已经决定,QueryPerformanceCounter可能是我最安全的赌注。 ( Boost::Posix
上的警告,它可能无法在Win32 API上工作,让我有点)。 但是,我不确定如何实现它。
我正在做的是调用我使用的任何GetTicks()
esque函数,并将其分配给Timer的startingTicks
变量。 然后找到过去的时间量,我只是从startingTicks
减去函数的返回值,当我重置计时器,我只是再次调用该函数,并将它分配的开始。 不幸的是,从我看到的代码不像调用QueryPerformanceCounter()
那么简单,我不知道我应该通过什么作为它的参数。
#include <windows.h> double PCFreq = 0.0; __int64 CounterStart = 0; void StartCounter() { LARGE_INTEGER li; if(!QueryPerformanceFrequency(&li)) cout << "QueryPerformanceFrequency failed!\n"; PCFreq = double(li.QuadPart)/1000.0; QueryPerformanceCounter(&li); CounterStart = li.QuadPart; } double GetCounter() { LARGE_INTEGER li; QueryPerformanceCounter(&li); return double(li.QuadPart-CounterStart)/PCFreq; } int main() { StartCounter(); Sleep(1000); cout << GetCounter() <<"\n"; return 0; }
这个程序应该输出一个接近1000的数字(windows睡眠不是那么准确,但应该是999)。
StartCounter()
函数记录性能计数器在CounterStart
变量中的滴答数。 GetCounter()
函数返回自从StartCounter()
最后一次被调用为double以来的毫秒数,所以如果GetCounter()
返回0.001,那么自从调用StartCounter()
后已经大约1微秒。
如果你想让计时器使用秒,而不是改变
PCFreq = double(li.QuadPart)/1000.0;
至
PCFreq = double(li.QuadPart);
或者如果你想微秒,然后使用
PCFreq = double(li.QuadPart)/1000000.0;
但实际上这是关于方便,因为它返回一倍。
我使用这些定义:
/** Use to init the clock */ #define TIMER_INIT \ LARGE_INTEGER frequency; \ LARGE_INTEGER t1,t2; \ double elapsedTime; \ QueryPerformanceFrequency(&frequency); /** Use to start the performance timer */ #define TIMER_START QueryPerformanceCounter(&t1); /** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */ #define TIMER_STOP \ QueryPerformanceCounter(&t2); \ elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart; \ std::wcout<<elapsedTime<<L" sec"<<endl;
用法(括号防止重新定义):
TIMER_INIT { TIMER_START Sleep(1000); TIMER_STOP } { TIMER_START Sleep(1234); TIMER_STOP }
使用示例中的输出:
1.00003 sec 1.23407 sec
假设你在Windows上(如果是的话,你应该这样标记你的问题!),在这个MSDN页面上,你可以找到一个简单的,有用的HRTimer
C ++类的源代码,包装所需的系统调用做一些非常接近你需要(可以很容易地添加一个GetTicks()
方法,特别是做你需要的)。
在非Windows平台上,不存在QueryPerformanceCounter函数,因此该解决方案不能直接移植。 然而,如果你把它封装在类如上面提到的HRTimer
,那么改变类的实现来使用当前平台确实能够提供的东西(可能通过Boost或者其他东西)会更容易。
我会用一个NDIS驱动程序的例子来扩展这个问题,以获得时间。 正如人们所知,KeQuerySystemTime(在NdisGetCurrentSystemTime下模拟)的分辨率低于毫秒,还有一些像网络数据包或其他IRP这样的进程可能需要更好的时间戳。
这个例子很简单:
LONG_INTEGER data, frequency; LONGLONG diff; data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency) diff = data.QuadPart / (Frequency.QuadPart/$divisor)
除数是10 ^ 3,或10 ^ 6取决于要求的分辨率。