如何使用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取决于要求的分辨率。