Como usar o QueryPerformanceCounter?

Eu recentemente decidi que eu precisava mudar de usar milissegundos para microssegundos para minha aula de Timer, e depois de algumas pesquisas eu decidi que QueryPerformanceCounter é provavelmente a minha aposta mais segura. (O aviso em Boost::Posix que pode não funcionar na API do Win32 me coloca um pouco fora). No entanto, não tenho certeza de como implementá-lo.

O que estou fazendo é chamar qualquer function GetTicks() que estou usando e atribuí-la à variável startingTicks do Timer. Então, para encontrar a quantidade de tempo passada, apenas subtraio o valor de retorno da function dos starts startingTicks , e quando eu zerar o timer, apenas chamo a function novamente e atribuo startTicks a ela. Infelizmente, a partir do código que vi, não é tão simples quanto apenas chamar QueryPerformanceCounter() , e não tenho certeza do que devo passar 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 programa deve produzir um número próximo de 1000 (o Windows Sleep não é tão preciso, mas deve ser como 999).

    A function StartCounter() registra o número de pulsos que o contador de desempenho tem na variável CounterStart . A function GetCounter() retorna o número de milissegundos desde que o StartCounter() foi chamado pela última vez como double, portanto, se GetCounter() retornar 0.001, ele StartCounter() sido aproximadamente 1 microssegundo desde que StartCounter() foi chamado.

    Se você quiser que o timer use segundos em vez disso, mude

     PCFreq = double(li.QuadPart)/1000.0; 

    para

     PCFreq = double(li.QuadPart); 

    ou se você quiser microssegundos, então use

     PCFreq = double(li.QuadPart)/1000000.0; 

    Mas realmente é sobre conveniência, uma vez que retorna um duplo.

    Eu uso estes 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 (colchetes para evitar redefinições):

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

    Saída do exemplo de uso:

     1.00003 sec 1.23407 sec 

    Supondo que você esteja no Windows (se for assim você deve marcar sua pergunta como tal!), Nesta página do MSDN você pode encontrar a fonte para uma class HRTimer C ++ simples e útil que envolve as chamadas de sistema necessárias para fazer algo muito próximo do que você require (seria fácil adicionar um método GetTicks() a ele, em particular, para fazer exatamente o que você precisa).

    Em plataformas não Windows, não há nenhuma function QueryPerformanceCounter, portanto, a solução não será diretamente portável. No entanto, se você envolvê-lo em uma class como o HRTimer mencionado HRTimer , será mais fácil alterar a implementação da class para usar o que a plataforma atual é realmente capaz de oferecer (talvez por meio do Boost ou qualquer outra coisa!).

    Eu iria estender esta questão com um exemplo de driver NDIS em obter tempo. Como se sabe, o KeQuerySystemTime (imitado em NdisGetCurrentSystemTime) tem uma baixa resolução acima de milissegundos, e existem alguns processos como pacotes de rede ou outros IRPs que podem precisar de um melhor timestamp;

    O exemplo é tão simples:

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

    onde divisor é 10 ^ 3 ou 10 ^ 6 dependendo da resolução requerida.