Come usare QueryPerformanceCounter?

Recentemente ho deciso che dovevo passare dall’uso di millisecondi a microsecondi per la mia class Timer e, dopo alcune ricerche, ho deciso che QueryPerformanceCounter è probabilmente la mia scommessa più sicura. (L’avvertenza su Boost::Posix che potrebbe non funzionare su Win32 API mi ha spinto un po ‘). Tuttavia, non sono davvero sicuro di come implementarlo.

Quello che sto facendo è chiamare la funzione esque di GetTicks() che sto usando e assegnarla alla variabile startingTicks di Timer. Quindi per trovare la quantità di tempo trascorso ho appena sottratto il valore di ritorno della funzione dagli startingTicks , e quando resetto il timer, richiamo di nuovo la funzione e assegnerò startTicks ad esso. Sfortunatamente, dal codice che ho visto non è così semplice come solo chiamare QueryPerformanceCounter() , e non sono sicuro di quello che dovrei passare come argomento.

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

Questo programma dovrebbe produrre un numero vicino a 1000 (il sonno di Windows non è accurato, ma dovrebbe essere come 999).

La funzione StartCounter() registra il numero di tick del contatore delle prestazioni nella variabile CounterStart . La funzione GetCounter() restituisce il numero di millisecondi da quando StartCounter() stato chiamato l'ultima volta come double, quindi se GetCounter() restituisce 0.001, è stato circa 1 microsecondo da StartCounter() stato chiamato StartCounter() .

Se vuoi che il timer usi secondi invece di cambiare

 PCFreq = double(li.QuadPart)/1000.0; 

a

 PCFreq = double(li.QuadPart); 

o se vuoi usare i microsecondi

 PCFreq = double(li.QuadPart)/1000000.0; 

Ma in realtà si tratta di convenienza dal momento che restituisce un doppio.

Io uso questi definisce:

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

Utilizzo (parentesi per evitare ridefinizioni):

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

Output dall'esempio di utilizzo:

 1.00003 sec 1.23407 sec 

Supponendo che tu sia su Windows (in tal caso dovresti taggare la tua domanda in quanto tale!), Su questa pagina MSDN puoi trovare la fonte per una semplice, utile class HRTimer C ++ che avvolge le chiamate di sistema necessarie per fare qualcosa di molto vicino a quello che richiedere (sarebbe facile aggiungere un metodo GetTicks() ad esso, in particolare, per fare esattamente ciò che si richiede).

Su piattaforms non Windows, non esiste alcuna funzione QueryPerformanceCounter, quindi la soluzione non sarà direttamente trasferibile. Tuttavia, se lo si avvolge in una class come il summenzionato HRTimer , sarà più facile cambiare l’implementazione della class per utilizzare ciò che la piattaforma corrente è effettivamente in grado di offrire (magari tramite Boost o qualsiasi altra cosa!).

Vorrei estendere questa domanda con un esempio di driver NDIS per ottenere tempo. Come si sa, KeQuerySystemTime (imitato in NdisGetCurrentSystemTime) ha una bassa risoluzione sopra i millisecondi, e ci sono alcuni processi come pacchetti di rete o altri IRP che potrebbero richiedere un timestamp migliore;

L’esempio è altrettanto semplice:

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

dove il divisore è 10 ^ 3 o 10 ^ 6 a seconda della risoluzione richiesta.