Pergunta

Usando apenas ANSI C, existe alguma maneira de medir o tempo com precisão milissegundos ou mais? Eu estava navegando time.h mas eu só encontrei funções segunda precisão.

Foi útil?

Solução

Não há nenhuma função ANSI C que proporciona melhor de 1 segundo resolução de tempo, mas a função POSIX gettimeofday fornece microssegundo resolução. A função de relógio mede apenas a quantidade de tempo que um processo passou execução e não é precisa em muitos sistemas.

Você pode usar esta função como esta:

struct timeval tval_before, tval_after, tval_result;

gettimeofday(&tval_before, NULL);

// Some code you want to time, for example:
sleep(1);

gettimeofday(&tval_after, NULL);

timersub(&tval_after, &tval_before, &tval_result);

printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);

Isso retorna Time elapsed: 1.000870 na minha máquina.

Outras dicas

#include <time.h>
clock_t uptime = clock() / (CLOCKS_PER_SEC / 1000);

Eu sempre uso a função clock_gettime (), retornando o tempo do relógio CLOCK_MONOTONIC. O tempo retornado é a quantidade de tempo, em segundos e nanosegundos, desde algum ponto não especificado no passado, tais como a inicialização do sistema da época.

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

int64_t timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
  return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
           ((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}

int main(int argc, char **argv)
{
  struct timespec start, end;
  clock_gettime(CLOCK_MONOTONIC, &start);

  // Some code I am interested in measuring 

  clock_gettime(CLOCK_MONOTONIC, &end);

  uint64_t timeElapsed = timespecDiff(&end, &start);
}

A implementação de uma solução portátil

Como já foi mencionado aqui que não há solução ANSI adequada com precisão suficiente para o problema de medição do tempo, eu quero escrever sobre as maneiras como obter um portátil e, se possível, uma solução de medição do tempo de alta resolução.

selos monotônica tempo relógio vs.

De um modo geral, há duas formas de medição do tempo:

  • relógio monotônica;
  • atual (data) carimbo de tempo.

O primeiro usa um contador de relógio monotônica (às vezes é chamado de contador de escala), que conta carrapatos com uma frequência pré-definida, por isso, se você tem um valor carrapatos ea freqüência é conhecido, você pode facilmente converter carrapatos ao tempo decorrido. realmente não é garantido que um relógio monotônica reflete a hora atual do sistema de qualquer forma, também pode contar tiques desde a inicialização do sistema. Mas ela garante que um relógio é sempre correr para cima de forma a aumentar, independentemente do estado do sistema. Normalmente, a frequência está ligado a uma fonte de alta-resolução de hardware, por isso é que ele fornece uma alta precisão (depende do hardware, mas a maior parte do hardware moderno não tem problemas com fontes de relógio de alta resolução).

A segunda maneira fornece uma (data) valor de tempo com base no valor do relógio do sistema atual. Pode também ter uma alta resolução, mas tem uma grande desvantagem: este tipo de valor de tempo pode ser afetada por diferentes ajustes de horário do sistema, ou seja, mudança de fuso horário, o horário de verão (DST) alterar, atualizar servidor NTP, hibernação do sistema e assim em. Em algumas circunstâncias, você pode obter um valor de tempo decorrido negativa que pode levar a um comportamento indefinido. Na verdade, este tipo de fonte de tempo é menos confiável do que o primeiro.

Assim, a primeira regra na medição intervalo de tempo é usar um relógio monótona, se possível. Ele geralmente tem uma alta precisão, e ele está seguro por design.

estratégia de emergência

Ao implementar uma solução portátil que vale a pena considerar uma estratégia de emergência:. Usar um relógio monotônica se disponível e retorno para o tempo selos aproximar, se não houver relógio monotônica no sistema

Windows

Há um ótimo artigo chamado a aquisição de alta resolução carimbos de tempo no MSDN sobre medição de tempo em Windows, que descreve todos os detalhes que você pode precisar de saber sobre software e suporte de hardware. Para adquirir um carimbo de tempo de alta precisão no Windows, você deve:

  • consulta um temporizador frequência (carrapatos por segundo) com QueryPerformanceFrequency :

    LARGE_INTEGER tcounter;
    LARGE_INTEGER freq;    
    
    if (QueryPerformanceFrequency (&tcounter) != 0)
        freq = tcounter.QuadPart;
    

    A frequência de temporizador é fixo na inicialização do sistema, então você precisa para obtê-lo apenas uma vez.

  • consulta o valor carrapatos atual com QueryPerformanceCounter :

    LARGE_INTEGER tcounter;
    LARGE_INTEGER tick_value;
    
    if (QueryPerformanceCounter (&tcounter) != 0)
        tick_value = tcounter.QuadPart;
    
  • dimensionar os carrapatos ao tempo decorrido, i para microssegundos:

    LARGE_INTEGER usecs = (tick_value - prev_tick_value) / (freq / 1000000);
    

De acordo com a Microsoft você não deve ter quaisquer problemas com esta abordagem no Windows XP e versões posteriores, na maioria dos casos. Mas você também pode usar duas soluções de recurso no Windows:

  • GetTickCount fornece o número de milissegundos que se passaram desde que o sistema Começou. Ela envolve a cada 49,7 dias, por isso tenha cuidado em medir intervalos mais longos.
  • GetTickCount64 é uma versão do GetTickCount de 64 bits, mas está começando disponível a partir do Windows Vista e acima.

OS X (MacOS)

OS X (MacOS) tem suas próprias unidades de tempo absoluto Mach que representam um relógio monótona. A melhor maneira de começar é o artigo o da Apple Técnico Q & A QA1398: Mach Absolute Time Units que descreve (com exemplos de código) como usar API específica de Mach para obter carrapatos monótonas. Há também uma questão local sobre isso chamado no Mac OS X que no final pode deixá-lo um pouco confuso o que fazer com o possível estouro de valor porque a freqüência contador é usado na forma de numerador eo denominador. Assim, um pequeno exemplo como conseguir tempo decorrido:

  • obter o numerador relógio frequência e denominador:

    #include <mach/mach_time.h>
    #include <stdint.h>
    
    static uint64_t freq_num   = 0;
    static uint64_t freq_denom = 0;
    
    void init_clock_frequency ()
    {
        mach_timebase_info_data_t tb;
    
        if (mach_timebase_info (&tb) == KERN_SUCCESS && tb.denom != 0) {
            freq_num   = (uint64_t) tb.numer;
            freq_denom = (uint64_t) tb.denom;
        }
    }
    

    Você precisa fazer isso apenas uma vez.

  • consulta o valor de escala atual com mach_absolute_time:

    uint64_t tick_value = mach_absolute_time ();
    
  • dimensionar os carrapatos ao tempo decorrido, i para microssegundos, usando numerador e o denominador anteriormente consultado:

    uint64_t value_diff = tick_value - prev_tick_value;
    
    /* To prevent overflow */
    value_diff /= 1000;
    
    value_diff *= freq_num;
    value_diff /= freq_denom;
    

    A idéia principal para evitar um transbordamento é de reduzir os carrapatos a precisão desejada antes de usar o numerador eo denominador. Como a resolução inicial temporizador está em nanossegundos, que dividi-lo por 1000 para obter microssegundos. Você pode encontrar a mesma abordagem utilizada no Chromium é time_mac.c . Se você realmente precisa de uma precisão de nanossegundos considere a leitura do Como posso usar mach_absolute_time sem transbordar? .

Linux e UNIX

A chamada clock_gettime é a sua melhor forma em qualquer sistema simpático-POSIX. É possível consultar o tempo a partir de diferentes fontes de relógio, e a necessidade que nós é CLOCK_MONOTONIC. Nem todos os sistemas que têm clock_gettime apoio CLOCK_MONOTONIC, então a primeira coisa que você precisa fazer é verificar sua disponibilidade:

  • se _POSIX_MONOTONIC_CLOCK é definido como um >= 0 valor significa que CLOCK_MONOTONIC é disponíveis;
  • Se _POSIX_MONOTONIC_CLOCK é definido para 0 isso significa que você deve também verificar se ele funciona em tempo de execução, sugiro a utilização sysconf:

    #include <unistd.h>
    
    #ifdef _SC_MONOTONIC_CLOCK
    if (sysconf (_SC_MONOTONIC_CLOCK) > 0) {
        /* A monotonic clock presents */
    }
    #endif
    
  • Caso contrário, um relógio monótona não é suportado e você deve usar uma estratégia de fallback (ver abaixo).

O uso de clock_gettime é bastante simples:

  • obter o valor de tempo:

    #include <time.h>
    #include <sys/time.h>
    #include <stdint.h>
    
    uint64_t get_posix_clock_time ()
    {
        struct timespec ts;
    
        if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
            return (uint64_t) (ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
        else
            return 0;
    }
    

    Eu já reduzida a hora de microssegundos aqui.

  • calcular a diferença com o valor de tempo anterior recebida da mesma maneira:

    uint64_t prev_time_value, time_value;
    uint64_t time_diff;
    
    /* Initial time */
    prev_time_value = get_posix_clock_time ();
    
    /* Do some work here */
    
    /* Final time */
    time_value = get_posix_clock_time ();
    
    /* Time difference */
    time_diff = time_value - prev_time_value;
    

A melhor estratégia fallback é usar a chamada gettimeofday: não é uma monótona, mas fornece muito boa resolução. A idéia é o mesmo que com clock_gettime, mas para obter um valor de tempo, você deve:

#include <time.h>
#include <sys/time.h>
#include <stdint.h>

uint64_t get_gtod_clock_time ()
{
    struct timeval tv;

    if (gettimeofday (&tv, NULL) == 0)
        return (uint64_t) (tv.tv_sec * 1000000 + tv.tv_usec);
    else
        return 0;
}

Novamente, o valor de tempo é reduzida para microssegundos.

SGI IRIX

IRIX tem a chamada clock_gettime, mas falta-lhe CLOCK_MONOTONIC. Em vez disso, tem a sua própria fonte de relógio monótona definida como CLOCK_SGI_CYCLE que você deve usar em vez de CLOCK_MONOTONIC com clock_gettime.

Solaris e HP-UX

Solaris tem a sua própria gethrtime interface de alta-resolução do temporizador que retorna o valor atual do temporizador em nanossegundos. Embora as versões mais recentes do Solaris pode ter clock_gettime, você pode furar a gethrtime se você precisa para suportar versões antigas do Solaris.

O uso é simples:

#include <sys/time.h>

void time_measure_example ()
{
    hrtime_t prev_time_value, time_value;
    hrtime_t time_diff;

    /* Initial time */
    prev_time_value = gethrtime ();

    /* Do some work here */

    /* Final time */
    time_value = gethrtime ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

HP-UX carece clock_gettime, mas ele suporta gethrtime que você deve usar da mesma forma como no Solaris.

BeOS

BeOS também tem seu próprio system_time interface de alta-resolução do temporizador que retorna o número de microssegundos têm decorrido desde que o computador foi iniciado.

Exemplo de utilização:

#include <kernel/OS.h>

void time_measure_example ()
{
    bigtime_t prev_time_value, time_value;
    bigtime_t time_diff;

    /* Initial time */
    prev_time_value = system_time ();

    /* Do some work here */

    /* Final time */
    time_value = system_time ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

OS / 2

OS / 2 tem sua própria API para recuperar selos de tempo de alta precisão:

  • consulta um temporizador de frequência (carrapatos por unidade) com DosTmrQueryFreq (por compilador GCC):

    #define INCL_DOSPROFILE
    #define INCL_DOSERRORS
    #include <os2.h>
    #include <stdint.h>
    
    ULONG freq;
    
    DosTmrQueryFreq (&freq);
    
  • consulta a corrente carrapatos valor com DosTmrQueryTime:

    QWORD    tcounter;
    unit64_t time_low;
    unit64_t time_high;
    unit64_t timestamp;
    
    if (DosTmrQueryTime (&tcounter) == NO_ERROR) {
        time_low  = (unit64_t) tcounter.ulLo;
        time_high = (unit64_t) tcounter.ulHi;
    
        timestamp = (time_high << 32) | time_low;
    }
    
  • dimensionar os carrapatos ao tempo decorrido, i para microssegundos:

    uint64_t usecs = (prev_timestamp - timestamp) / (freq / 1000000);
    

Exemplo implementação

Você pode dar uma olhada no href="https://github.com/saprykin/plibsys" rel="noreferrer"> plibsys biblioteca que implementa todas as descrito acima estratégias (ver ptimeprofiler * .c para detalhes).

timespec_get de C11

Retorna até nanosegundos, arredondado para a resolução da implementação.

Parece um ANSI ripoff de clock_gettime POSIX'.

Exemplo: a printf é feito a cada 100ms no Ubuntu 15.10:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static long get_nanos(void) {
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    return (long)ts.tv_sec * 1000000000L + ts.tv_nsec;
}

int main(void) {
    long nanos;
    long last_nanos;
    long start;
    nanos = get_nanos();
    last_nanos = nanos;
    start = nanos;
    while (1) {
        nanos = get_nanos();
        if (nanos - last_nanos > 100000000L) {
            printf("current nanos: %ld\n", nanos - start);
            last_nanos = nanos;
        }
    }
    return EXIT_SUCCESS;
}

O C11 N1570 padrão projecto 7.27.2.5 "A função timespec_get diz":

Se a base é TIME_UTC, o membro tv_sec está definido para o número de segundos desde uma implementação época definida, truncado para um valor inteiro e o membro tv_nsec é conjunto com o integrante do número de nanossegundos, arredondado para a resolução do relógio do sistema. (321)

321) Embora um objeto timespec struct descreve vezes com resolução de nanossegundos, o disponível resolução é dependente do sistema e pode mesmo ser maior do que 1 segundo.

C ++ 11 std::chrono::high_resolution_clock também tem: C ++ Cross-Platform alta resolução Temporizador

glibc 2.21 implementação

Pode ser encontrado em sysdeps/posix/timespec_get.c como:

int
timespec_get (struct timespec *ts, int base)
{
  switch (base)
    {
    case TIME_UTC:
      if (__clock_gettime (CLOCK_REALTIME, ts) < 0)
        return 0;
      break;

    default:
      return 0;
    }

  return base;
}

tão claramente:

  • única TIME_UTC é actualmente suportado

  • -lo para a frente para __clock_gettime (CLOCK_REALTIME, ts), que é uma API POSIX: http : //pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html

    Linux x86-64 tem uma chamada de sistema clock_gettime.

    Note que este não é um método à prova de falhas, análise comparativa micro porque:

    • man clock_gettime diz que esta medida pode ter descontinuidades se você mudar alguma configuração hora do sistema enquanto o programa é executado. Este deve ser um evento raro, é claro, e você pode ser capaz de ignorá-lo.

    • Neste momento parede medidas, por isso, se o programador decide esquecer sua tarefa, ele aparecerá para ser executado por mais tempo.

    Para aqueles razões getrusage() pode ser uma melhor melhor ferramenta de benchmarking POSIX, apesar da sua menor máxima precisão microssegundo.

    Mais informações em: vez em Linux -? tempo vs relógio vs getrusage vs clock_gettime vs gettimeofday vs timespec_get

A melhor precisão que você pode, possivelmente, obter é através do uso do x86 somente instrução "rdtsc", que pode fornecer resolução de nível relógio (ne deve, naturalmente, tomar em consideração o custo da própria chamada rdtsc, que pode ser medido facilmente na inicialização do aplicativo).

O problema principal aqui é medir o número de relógios por segundo, o que não deve ser muito difícil.

A resposta aceita é bom enough.But minha solução é mais simple.I apenas de teste no Linux, use gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.

Alse uso gettimeofday, o tv_sec é a parte do segundo, eo tv_usec é microssegundos , não milissegundos .

long currentTimeMillis() {
  struct timeval time;
  gettimeofday(&time, NULL);

  return time.tv_sec * 1000 + time.tv_usec / 1000;
}

int main() {
  printf("%ld\n", currentTimeMillis());
  // wait 1 second
  sleep(1);
  printf("%ld\n", currentTimeMillis());
  return 0;
 }

imprimir:

1522139691342 1522139692342, exatamente um segundo.

Sob janelas:

SYSTEMTIME t;
GetLocalTime(&t);
swprintf_s(buff, L"[%02d:%02d:%02d:%d]\t", t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top