Desejo calcular o tempo que levou para uma API retornar um valor. O tempo gasto para tal ação é de nano segundos. Como a API é uma classe / função C ++, estou usando o timer.h para calcular o mesmo:
#include <ctime>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
clock_t start;
double diff;
start = clock();
diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
cout<<"printf: "<< diff <<'\n';
return 0;
}
O código acima fornece o tempo em segundos. Como faço para obter o mesmo em nano segundos e com mais precisão?
clock()
não é tão rápido quanto eu pensava.Respostas:
O que outros postaram sobre como executar a função repetidamente em um loop está correto.
Para Linux (e BSD), você deseja usar clock_gettime () .
Para janelas, você deseja usar o QueryPerformanceCounter . E aqui está mais sobre QPC
Aparentemente, há um problema conhecido com o QPC em alguns chipsets, portanto, verifique se você não tem esses chipset. Além disso, alguns AMDs de núcleo duplo também podem causar problemas . Veja a segunda postagem do sebbbi, onde ele afirma:
EDITAR 16/07/2013:
Parece que há alguma controvérsia sobre a eficácia do QPC sob certas circunstâncias, conforme declarado em http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx
No entanto, esta resposta do StackOverflow https://stackoverflow.com/a/4588605/34329 afirma que o QPC deve funcionar bem em qualquer sistema operacional MS após o service pack 2 do Win XP.
Este artigo mostra que o Windows 7 pode determinar se o (s) processador (es) têm um TSC invariável e recorre a um cronômetro externo se não tiver. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html A sincronização entre processadores ainda é um problema.
Outra boa leitura relacionada a temporizadores:
Veja os comentários para mais detalhes.
fonte
CLOCK_MONOTONIC_RAW
, se estiver disponível, para obter o tempo de hardware não ajustado pelo NTP.Essa nova resposta usa os recursos do C ++ 11
<chrono>
. Embora existam outras respostas que mostram como usar<chrono>
, nenhuma delas mostra como usar<chrono>
com aRDTSC
facilidade mencionada em várias das outras respostas aqui. Então pensei em mostrar como usarRDTSC
com<chrono>
. Além disso eu vou demonstrar como você pode templatize o código de teste no relógio de modo que você pode alternar rapidamente entreRDTSC
e seu sistema está integrado em instalações de clock (que provavelmente será baseado emclock()
,clock_gettime()
e / ouQueryPerformanceCounter
.Observe que a
RDTSC
instrução é específica para x86.QueryPerformanceCounter
é apenas para Windows. Eclock_gettime()
é apenas POSIX. A seguir, apresento dois novos relógios:std::chrono::high_resolution_clock
andstd::chrono::system_clock
, que, se você pode assumir o C ++ 11, agora são multiplataforma.Primeiro, aqui está como você cria um relógio compatível com C ++ 11 a partir das
rdtsc
instruções de montagem da Intel . Eu vou chamá-lox::clock
:Tudo o que esse relógio faz é contar os ciclos da CPU e armazená-los em um inteiro não assinado de 64 bits. Você pode precisar ajustar a sintaxe da linguagem assembly para o seu compilador. Ou seu compilador pode oferecer um intrínseco que você pode usar em seu lugar (por exemplo
now() {return __rdtsc();}
).Para construir um relógio, você deve dar a ele a representação (tipo de armazenamento). Você também deve fornecer o período de clock, que deve ser uma constante de tempo de compilação, mesmo que sua máquina possa alterar a velocidade do clock em diferentes modos de energia. E, a partir deles, você pode definir facilmente a duração e o ponto de tempo "nativo" do seu relógio em termos desses fundamentos.
Se tudo o que você deseja fazer é mostrar o número de tiques do relógio, realmente não importa o número fornecido para o período do relógio. Essa constante só entra em ação se você quiser converter o número de tiques do relógio em alguma unidade de tempo real, como nanossegundos. E, nesse caso, quanto mais preciso você for capaz de fornecer a velocidade do clock, mais precisa será a conversão em nanossegundos (milissegundos, o que for).
Abaixo está o código de exemplo que mostra como usar
x::clock
. Na verdade, criei um modelo para o código do relógio, pois gostaria de mostrar como você pode usar muitos relógios diferentes com a mesma sintaxe exata. Este teste específico está mostrando qual é a sobrecarga do loop ao executar o que você deseja cronometrar em um loop:A primeira coisa que esse código faz é criar uma unidade de "tempo real" para exibir os resultados. Eu escolhi picossegundos, mas você pode escolher qualquer unidade que desejar, seja integral ou baseada em ponto flutuante. Como exemplo, há uma
std::chrono::nanoseconds
unidade pré-fabricada que eu poderia ter usado.Como outro exemplo, quero imprimir o número médio de ciclos de clock por iteração como um ponto flutuante, então crio outra duração, com base em double, que tem as mesmas unidades que o tique do relógio (chamado
Cycle
no código).O loop é cronometrado com chamadas para
clock::now()
ambos os lados. Se você deseja nomear o tipo retornado por esta função, é:(como mostrado claramente no
x::clock
exemplo, e também é verdadeiro para os relógios fornecidos pelo sistema).Para obter uma duração em termos de tiques do relógio de ponto flutuante, basta subtrair os dois pontos no tempo e, para obter o valor por iteração, divida essa duração pelo número de iterações.
Você pode obter a contagem em qualquer duração usando a
count()
função de membro. Isso retorna a representação interna. Finalmente, costumostd::chrono::duration_cast
converter a duraçãoCycle
em duraçãopicoseconds
e imprimi-la.Usar este código é simples:
Acima, eu exercito o teste usando nosso feito em casa
x::clock
e comparo esses resultados com o uso de dois relógios fornecidos pelo sistema:std::chrono::high_resolution_clock
estd::chrono::system_clock
. Para mim, isso imprime:Isso mostra que cada um desses relógios tem um período de tique diferente, já que os tiques por iteração são muito diferentes para cada relógio. No entanto, quando convertido para uma unidade de tempo conhecida (por exemplo, picossegundos), obtenho aproximadamente o mesmo resultado para cada relógio (sua milhagem pode variar).
Observe como meu código está completamente livre de "constantes de conversão mágicas". Na verdade, existem apenas dois números mágicos em todo o exemplo:
x::clock
.fonte
rdtsc
relógio provavelmente terá conversões imprecisas para outras unidades. É uma boa ideia configurar suas medições de forma que você possa facilmente alterar e comparar os relógios (como mostrado nesta resposta).Com esse nível de precisão, seria melhor raciocinar no tique da CPU do que na chamada do sistema como clock () . E não se esqueça de que se levar mais de um nanossegundo para executar uma instrução ... ter uma precisão de nanossegundo é praticamente impossível.
Ainda assim, algo assim é um começo:
Aqui está o código real para recuperar o número de tiques do clock da CPU 80x86 passados desde a última inicialização da CPU. Ele funcionará no Pentium e superior (386/486 não compatível). Este código é, na verdade, específico do MS Visual C ++, mas provavelmente pode ser facilmente transportado para qualquer outro lugar, desde que suporte montagem embutida.
Esta função também tem a vantagem de ser extremamente rápida - normalmente não leva mais de 50 ciclos de CPU para ser executada.
Usando os números de tempo :
Se você precisar traduzir a contagem do relógio em tempo decorrido real, divida os resultados pela velocidade do relógio do seu chip. Lembre-se de que o GHz "nominal" provavelmente será um pouco diferente da velocidade real do seu chip. Para verificar a velocidade real do seu chip, você pode usar vários utilitários muito bons ou a chamada do Win32, QueryPerformanceFrequency ().
fonte
Para fazer isso corretamente, você pode usar uma das duas maneiras, ir com
RDTSC
ou comclock_gettime()
. O segundo é cerca de 2 vezes mais rápido e tem a vantagem de fornecer o tempo absoluto correto. Observe que paraRDTSC
funcionar corretamente, você precisa usá-lo conforme indicado (outros comentários nesta página contêm erros e podem resultar em valores de tempo incorretos em certos processadores)e para clock_gettime: (escolhi resolução de microssegundos arbitrariamente)
o tempo e os valores produzidos:
fonte
Estou usando o seguinte para obter os resultados desejados:
fonte
Para C ++ 11 , aqui está um wrapper simples:
Ou para C ++ 03 em * nix,
Exemplo de uso:
De https://gist.github.com/gongzhitaao/7062087
fonte
Em geral, para cronometrar quanto tempo leva para chamar uma função, você deseja fazer isso muito mais vezes do que apenas uma vez. Se você chamar sua função apenas uma vez e levar um tempo muito curto para ser executada, você ainda terá a sobrecarga de realmente chamar as funções do temporizador e não saberá quanto tempo isso levará.
Por exemplo, se você estima que sua função pode levar 800 ns para ser executada, chame-a em um loop dez milhões de vezes (o que levará cerca de 8 segundos). Divida o tempo total por dez milhões para obter o tempo por chamada.
fonte
Você pode usar a seguinte função com gcc em execução em processadores x86:
com Digital Mars C ++:
que lê o temporizador de alto desempenho no chip. Eu uso isso ao fazer perfis.
fonte
unsigned int
como tipo interno.Se precisar de precisão de subsegundo, você precisará usar extensões específicas do sistema e terá que verificar a documentação do sistema operacional. POSIX suporta até microssegundos com gettimeofday , mas nada mais preciso já que os computadores não tinham frequências acima de 1GHz.
Se você estiver usando Boost, você pode verificar boost :: posix_time .
fonte
Estou usando o código Borland aqui é o código que ti_hund me dá algumas vezes um número negativo, mas o tempo é bastante bom.
fonte
Usando o método de Brock Adams, com uma classe simples:
Exemplo de uso:
Resultado:
teste realizado: 0,0002 ms
Tem alguma sobrecarga de chamada de função, mas ainda deve ser mais do que rápido o suficiente :)
fonte
Você pode usar o Embedded Profiler (gratuito para Windows e Linux), que tem uma interface para um temporizador multiplataforma (em uma contagem de ciclos do processador) e pode fornecer um número de ciclos por segundos:
O recálculo da contagem do ciclo no tempo é possivelmente uma operação perigosa com processadores modernos onde a frequência da CPU pode ser alterada dinamicamente. Portanto, para ter certeza de que os tempos convertidos estão corretos, é necessário fixar a frequência do processador antes de criar o perfil.
fonte
Se for para Linux, estou usando a função "gettimeofday", que retorna uma estrutura que fornece os segundos e microssegundos desde a época. Você pode então usar timersub para subtrair os dois para obter a diferença de tempo e convertê-lo para a precisão de tempo que desejar. No entanto, você especifica nanossegundos e parece que a função clock_gettime () é o que você está procurando. Ele coloca o tempo em termos de segundos e nanossegundos na estrutura que você passa para ele.
fonte
O que você acha disso:
fonte
Aqui está um bom temporizador de Boost que funciona bem:
fonte
Copiar e colar minimalista + uso lento
Se a ideia é ter uma estrutura minimalista que você possa usar para testes rápidos, então sugiro que você apenas copie e cole em qualquer lugar do seu arquivo C ++ logo após o
#include
's. Este é o único caso em que sacrifico a formatação no estilo Allman.Você pode ajustar facilmente a precisão na primeira linha da estrutura. Os valores possíveis são:
nanoseconds
,microseconds
,milliseconds
,seconds
,minutes
, ouhours
.Uso
Resultado de saída padrão
Se você quiser um resumo após a execução
Se você quiser o relatório depois, porque, por exemplo, seu código intermediário também grava na saída padrão. Em seguida, adicione a seguinte função à estrutura (logo antes de MeasureTime ()):
Então você pode apenas usar:
Que listará todas as marcas como antes, mas depois que o outro código for executado. Observe que você não deve usar ambos
m.s()
em.t()
.fonte