¿Cómo usar QueryPerformanceCounter?

Hace poco decidí que necesitaba cambiar de milisegundos a microsegundos para mi clase de temporizador, y después de algunas investigaciones decidí que QueryPerformanceCounter es probablemente mi apuesta más segura. (La advertencia en Boost::Posix que puede no funcionar en la API de Win32 me desanimó un poco). Sin embargo, no estoy seguro de cómo implementarlo.

Lo que hago es llamar a la función GetTicks() esque que estoy usando y asignarla a la variable startingTicks de Timer. Luego, para calcular la cantidad de tiempo transcurrido, restamos el valor de retorno de la función de los Ticks startingTicks , y cuando restablezco el temporizador, simplemente llamo de nuevo a la función y le asigno StartingTicks. Desafortunadamente, del código que he visto no es tan simple como llamar a QueryPerformanceCounter() , y no estoy seguro de qué se supone que debo pasar como argumento.

 #include  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; } 

Este progtwig debería generar un número cercano a 1000 (el modo de suspensión de Windows no es tan preciso, pero debería ser como 999).

La función StartCounter() registra el número de tics que tiene el contador de rendimiento en la variable CounterStart . La función GetCounter() devuelve el número de milisegundos desde la última vez que se llamó a StartCounter() como un doble, por lo que si GetCounter() devuelve 0.001, ha sido de aproximadamente 1 microsegundo desde que se llamó a StartCounter() .

Si desea que el temporizador use segundos en su lugar, cambie

 PCFreq = double(li.QuadPart)/1000.0; 

a

 PCFreq = double(li.QuadPart); 

o si quiere microsegundos, use

 PCFreq = double(li.QuadPart)/1000000.0; 

Pero realmente se trata de conveniencia ya que devuelve un doble.

Yo uso estos define:

 /** 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<  

Uso (corchetes para evitar redefinir):

 TIMER_INIT { TIMER_START Sleep(1000); TIMER_STOP } { TIMER_START Sleep(1234); TIMER_STOP } 

Salida del ejemplo de uso:

 1.00003 sec 1.23407 sec 

Suponiendo que está en Windows (si es así, debe etiquetar su pregunta como tal), en esta página de MSDN puede encontrar el origen de una clase de HRTimer C ++ sencilla y útil que envuelve las llamadas al sistema necesarias para hacer algo muy parecido a lo que require (sería fácil agregarle un método GetTicks() , en particular, para hacer exactamente lo que necesita).

En plataformas que no son de Windows, no hay función QueryPerformanceCounter, por lo que la solución no será directamente portátil. Sin embargo, si lo envuelve en una clase como el HRTimer antes mencionado, será más fácil cambiar la implementación de la clase para usar lo que la plataforma actual puede ofrecer (¡quizás a través de Boost o lo que sea!).

Extendería esta pregunta con un ejemplo de controlador NDIS sobre cómo obtener tiempo. Como se sabe, KeQuerySystemTime (imitado en NdisGetCurrentSystemTime) tiene una resolución baja por encima de milisegundos, y hay algunos procesos como paquetes de red u otros IRP que pueden necesitar una mejor marca de tiempo;

El ejemplo es igual de simple:

 LONG_INTEGER data, frequency; LONGLONG diff; data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency) diff = data.QuadPart / (Frequency.QuadPart/$divisor) 

donde el divisor es 10 ^ 3 o 10 ^ 6 dependiendo de la resolución requerida.