Estou portando um jogo, que foi originalmente escrito para a API Win32, para o Linux (bem, portando a porta OS X da porta Win32 para o Linux).
Eu implementei QueryPerformanceCounter
dando os uSeconds desde o início do processo:
BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
gettimeofday(¤tTimeVal, NULL);
performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
performanceCount->QuadPart *= (1000 * 1000);
performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);
return true;
}
Isso, junto com QueryPerformanceFrequency()
dar um 1000000 constante como a frequência, funciona bem na minha máquina , dando-me uma variável de 64 bits que contém uSeconds
desde a inicialização do programa.
Então, isso é portátil? Não quero descobrir que funciona de maneira diferente se o kernel foi compilado de uma certa maneira ou algo parecido. Eu estou bem com ele não sendo portátil para algo diferente do Linux, no entanto.
Alta resolução, baixa sobrecarga para processadores Intel
Se você estiver usando um hardware Intel, veja como ler o contador de instruções da CPU em tempo real. Ele informará o número de ciclos da CPU executados desde que o processador foi inicializado. Este é provavelmente o contador mais refinado que você pode obter para medição de desempenho.
Observe que este é o número de ciclos da CPU. No Linux, você pode obter a velocidade da CPU em / proc / cpuinfo e dividir para obter o número de segundos. Converter isso em um duplo é bastante útil.
Quando eu executo isso na minha caixa, eu recebo
Aqui está o guia do desenvolvedor da Intel, que fornece muitos detalhes.
fonte
CPUID
novamente após a primeiraRDTSC
instrução e antes de executar o código que está sendo testado? Caso contrário, o que impede que o código de referência seja executado antes / em paralelo com o primeiroRDTSC
e, conseqüentemente, sub-representado noRDTSC
delta?@Bernard:
Boa pergunta ... Acho que o código está ok. Do ponto de vista prático, nós o usamos na minha empresa todos os dias e operamos em uma grande variedade de caixas, tudo de 2 a 8 núcleos. Claro, YMMV, etc, mas parece ser um método de temporização confiável e de baixo overhead (porque não faz uma mudança de contexto para o espaço do sistema).
Geralmente funciona assim:
Notas específicas:
a execução fora de ordem pode causar resultados incorretos, por isso executamos a instrução "cpuid" que, além de fornecer algumas informações sobre a CPU, também sincroniza qualquer execução de instrução fora de ordem.
A maioria dos sistemas operacionais sincroniza os contadores nas CPUs quando eles são iniciados, então a resposta é boa em alguns nano segundos.
O comentário de hibernação provavelmente é verdadeiro, mas na prática você provavelmente não se preocupa com os intervalos entre os limites de hibernação.
sobre speedstep: CPUs Intel mais recentes compensam as mudanças de velocidade e retorna uma contagem ajustada. Eu fiz uma varredura rápida em algumas das caixas em nossa rede e encontrei apenas uma caixa que não tinha: um Pentium 3 rodando algum servidor de banco de dados antigo. (são caixas de Linux, então verifiquei com: grep constant_tsc / proc / cpuinfo)
Não tenho certeza sobre as CPUs AMD, somos principalmente uma loja da Intel, embora eu saiba que alguns de nossos gurus de sistemas de baixo nível fizeram uma avaliação da AMD.
Espero que isso satisfaça sua curiosidade, é uma área de programação interessante e (IMHO) pouco estudada. Você sabe quando Jeff e Joel estavam conversando sobre se um programador deveria ou não saber C? Eu estava gritando com eles, "ei, esqueça essas coisas de C de alto nível ... assembler é o que você deve aprender se quiser saber o que o computador está fazendo!"
fonte
Você pode estar interessado no Linux FAQ para
clock_gettime(CLOCK_REALTIME)
fonte
O Wine está, na verdade, usando gettimeofday () para implementar QueryPerformanceCounter () e é conhecido por fazer muitos jogos do Windows funcionarem no Linux e no Mac.
Inicia http://source.winehq.org/source/dlls/kernel32/cpu.c#L312
leva a http://source.winehq.org/source/dlls/ntdll/time.c#L448
fonte
A estrutura de dados é definida como tendo microssegundos como unidade de medida, mas isso não significa que o relógio ou sistema operacional seja realmente capaz de medir isso com precisão.
Como outras pessoas sugeriram,
gettimeofday()
é ruim porque acertar a hora pode causar distorção do relógio e atrapalhar o cálculo.clock_gettime(CLOCK_MONOTONIC)
é o que você deseja eclock_getres()
lhe dirá a precisão do seu relógio.fonte
Obtive esta resposta na Medição de tempo e cronômetros de alta resolução, parte I
fonte
Esta resposta menciona problemas com o ajuste do relógio. Tanto seus problemas em garantir unidades de tick quanto os problemas com o tempo sendo ajustado são resolvidos em C ++ 11 com a
<chrono>
biblioteca.std::chrono::steady_clock
É garantido que o relógio não será ajustado e, além disso, avançará a uma taxa constante em relação ao tempo real, de modo que tecnologias como SpeedStep não devem afetá-lo.Você pode obter unidades typesafe convertendo para uma das
std::chrono::duration
especializações, comostd::chrono::microseconds
. Com esse tipo, não há ambigüidade sobre as unidades usadas pelo valor do tique. Porém, lembre-se de que o relógio não tem necessariamente esta resolução. Você pode converter uma duração em attossegundos sem realmente ter um relógio tão preciso.fonte
Pela minha experiência e pelo que li na Internet, a resposta é "Não", não é garantido. Depende da velocidade da CPU, sistema operacional, tipo de Linux, etc.
fonte
A leitura do RDTSC não é confiável em sistemas SMP, uma vez que cada CPU mantém seu próprio contador e cada contador não tem garantia de sincronização em relação a outra CPU.
Eu poderia sugerir tentar
clock_gettime(CLOCK_REALTIME)
. O manual posix indica que isso deve ser implementado em todos os sistemas compatíveis. Ele pode fornecer uma contagem de nanossegundos, mas você provavelmente desejará verificarclock_getres(CLOCK_REALTIME)
em seu sistema para ver qual é a resolução real.fonte
clock_getres(CLOCK_REALTIME)
não dará a resolução real. Sempre retorna "1 ns" (um nanossegundo) quando hrtimers estão disponíveis, verifique oinclude/linux/hrtimer.h
arquivo paradefine HIGH_RES_NSEC 1
(mais em stackoverflow.com/a/23044075/196561 )