É gettimeofday () garantia de ser de resolução de microsegundos?

votos
82

Eu sou portagem de um jogo, que foi originalmente escrito para a API Win32, para Linux (bem, portando o porto OS X do porto Win32 para Linux).

Eu tenho implementado QueryPerformanceCounter, dando os uSeconds vez que o processo de arranque:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

Isso, juntamente com QueryPerformanceFrequency()dando uma constante 1000000 como a freqüência, funciona bem na minha máquina , dando-me uma variável de 64 bits que contém uSecondsdesde que o programa arranque.

Então este é portátil? Eu não quero descobrir que funciona de forma diferente se o kernel foi compilado em uma determinada maneira ou qualquer coisa assim. Eu estou bem com ele sendo não-portáteis para algo diferente de Linux, no entanto.

Publicado 01/08/2008 em 15:36
fonte usuário
Em outras línguas...                            


10 respostas

votos
54

Talvez. Mas você tem problemas maiores. gettimeofday()pode resultar em horários incorretos se há processos em seu sistema que mudam o temporizador (ou seja, ntpd). Em um linux "normal", porém, acredito que a resolução de gettimeofday()é 10us. Ele pode saltar para a frente e para trás e tempo, consequentemente, com base nos processos em execução no seu sistema. Isso efetivamente faz com que a resposta à sua pergunta não.

Você deve olhar para clock_gettime(CLOCK_MONOTONIC)para cronometrar intervalos. Ele sofre de vários problemas menos devido a coisas como sistemas multi-core e definições do relógio externos.

Além disso, olhar para a clock_getres()função.

Respondeu 01/08/2008 em 15:53
fonte usuário

votos
39

Alta resolução, Baixo sincronismo Overhead para processadores Intel

Se você estiver em hardware Intel, aqui é como ler a CPU em tempo real contador de instruções. Vai dizer-lhe o número de ciclos de CPU executados desde o processador foi inicializado. Este é provavelmente o contador com granulação mais fina que você pode obter para medição de desempenho.

Note-se que este é o número de ciclos de CPU. No linux você pode obter a velocidade da CPU de / proc / cpuinfo e dividir para obter o número de segundos. Convertendo isso para um casal é bastante acessível.

Quando eu executar este na minha caixa, eu recebo

11867927879484732
11867927879692217
it took this long to call printf: 207485

Aqui está o guia do desenvolvedor Intel que lhe dá toneladas de detalhes.

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
Respondeu 02/08/2008 em 09:08
fonte usuário

votos
18

@Bernard:

Eu tenho que admitir, a maioria de seu exemplo foi direto sobre a minha cabeça. Ele faz compilar e parece funcionar, embora. É este seguro para sistemas SMP ou SpeedStep?

Essa é uma boa pergunta ... Eu acho que o código ok. Do ponto de vista prático, podemos usá-lo na minha empresa todos os dias, e corremos em uma muito grande variedade de caixas, tudo a partir de 2-8 núcleos. Claro, YMMV, etc, mas parece ser uma confiança e baixo-cima (uma vez que não faz uma mudança de contexto no sistema de espaço) método de sincronismo.

Geralmente como ele funciona é:

  • declarar o bloco de código para ser montador (e voláteis, de modo que o otimizador irá deixá-lo sozinho).
  • executar a instrução CPUID. Além de obter algumas informações CPU (que nós não fazemos nada com) ele sincroniza tampão execução da CPU para que os horários não são afetados pela execução de out-of-order.
  • executar o rdtsc execução (timestamp ler). Esta obtém o número de ciclos de máquina executadas desde que o processador foi zerado. Este é um valor de 64 bits, por isso, com velocidades de CPU atual que vai envolver em torno de cada 194 anos ou mais. Curiosamente, na referência Pentium original, eles observam que envolve a cada 5800 anos ou mais.
  • o último par de linhas de armazenar os valores dos registros nas variáveis ​​hi e lo e colocá-la no valor de retorno de 64 bits.

notas específicas:

  • fora-de-ordem de execução pode causar resultados incorretos, de modo que executar a instrução "cpuid", que além de dar-lhe algumas informações sobre a CPU também sincroniza toda a execução da instrução fora de ordem.

  • A maioria dos sistemas operacionais sincronizar os contadores no CPUs quando eles começam, então a resposta é boa para dentro de um par de nano-segundos.

  • O comentário hibernando é provavelmente verdade, mas na prática você provavelmente não se preocupam com horários através das fronteiras de hibernação.

  • sobre speedstep: mais recente Intel CPUs compensar as mudanças de velocidade e retorna uma contagem ajustada. Eu fiz uma verificação rápida sobre algumas das caixas em nossa rede e encontraram apenas uma caixa que não tem isso: um Pentium 3 rodando algum servidor de banco de dados antigo. (Estes são caixas de Linux, então eu verifiquei com: grep CONSTANT_TSC / proc / cpuinfo)

  • Eu não tenho certeza sobre os processadores da AMD, estamos principalmente uma loja de Intel, embora eu saiba que alguns dos nossos gurus de sistemas de baixo nível fez uma avaliação AMD.

Espero que isso satisfaz a sua curiosidade, é uma área interessante e (IMHO) sob estudado de programação. Você sabe quando Jeff e Joel estavam falando sobre se deve ou não um programador deve saber C? Eu estava gritando com eles, "hey esquecer essas coisas de alto nível C ... montador é o que você deve saber se você quer saber o que o computador está fazendo!"

Respondeu 04/08/2008 em 01:51
fonte usuário

votos
14

Você pode estar interessado em Linux FAQ paraclock_gettime(CLOCK_REALTIME)

Respondeu 18/08/2008 em 16:51
fonte usuário

votos
11

Vinho está realmente usando gettimeofday () para implementar QueryPerformanceCounter () e ele é conhecido por fazer muitos jogos do Windows funciona em Linux e Mac.

inicia http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

leva a http://source.winehq.org/source/dlls/ntdll/time.c#L448

Respondeu 04/08/2008 em 15:44
fonte usuário

votos
9

Por isso, diz microssegundos explicitamente, mas diz que a resolução do relógio do sistema é indeterminado. Suponho resolução neste contexto significa como a menor quantidade que nunca vai ser incrementado?

A estrutura de dados é definida como tendo microssegundos como uma unidade de medida, mas isso não quer dizer que o relógio do sistema operacional ou é realmente capaz de medir que finamente.

Como outras pessoas têm sugerido, gettimeofday()é ruim porque a definição do tempo pode causar a inclinação do clock e jogar fora o seu cálculo. clock_gettime(CLOCK_MONOTONIC)é o que você quer, e clock_getres()irá dizer-lhe a precisão de seu relógio.

Respondeu 02/08/2008 em 18:57
fonte usuário

votos
8

A resolução real de gettimeofday () depende da arquitetura de hardware. processadores Intel, bem como máquinas SPARC oferecer temporizadores de alta resolução que medem microssegundos. Outras arquiteturas de hardware cair de volta para o temporizador do sistema, que normalmente é definido para 100 Hz. Nesses casos, a resolução de tempo vai ser menos precisas.

I obteve esta resposta de alta resolução temporal Medição e Timers, Parte I

Respondeu 01/08/2008 em 15:55
fonte usuário

votos
5

Esta resposta menciona problemas com o relógio a ser ajustado. Ambos os seus problemas, garantindo unidades de carrapatos e os problemas com o tempo sendo ajustado são resolvidos em C ++ 11 com a <chrono>biblioteca.

O relógio std::chrono::steady_clocknão é garantido para ser ajustada, e, além disso, vai avançar a uma taxa relativamente constante de tempo real, para tecnologias como SpeedStep não deve afetá-lo.

Você pode obter unidades typesafe convertendo a uma das std::chrono::durationespecializações, tais como std::chrono::microseconds. Com este tipo não há nenhuma ambigüidade sobre as unidades usadas pelo valor carrapato. No entanto, tenha em mente que o relógio não tem necessariamente desta resolução. Você pode converter uma duração de attoseconds sem realmente ter um relógio que precisa.

Respondeu 26/06/2012 em 16:57
fonte usuário

votos
4

Da minha experiência, e pelo que eu li em toda a Internet, a resposta é "Não", não é garantido. Depende da velocidade da CPU, o sistema operacional, o sabor de Linux, etc.

Respondeu 01/08/2008 em 15:46
fonte usuário

votos
3

Lendo o RDTSC não é confiável em sistemas SMP, uma vez que cada CPU mantém seu próprio contador e cada contador não é garantido que pelo sincronizado com respeito a outra CPU.

Eu poderia sugerir tentando clock_gettime(CLOCK_REALTIME). O manual POSIX indica que este deve ser implementada em todos os sistemas compatíveis. Ele pode fornecer uma contagem nanosegundo, mas você provavelmente vai querer verificar clock_getres(CLOCK_REALTIME)em seu sistema para ver o que a resolução real é.

Respondeu 18/08/2008 em 16:40
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more