Meça o tempo no Linux - hora vs relógio vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?

148

Entre as funções de temporização, time, clock getrusage, clock_gettime, gettimeofdaye timespec_get, eu quero entender claramente como eles são implementados e quais são os seus valores de retorno a fim de saber em que situação eu tenho que usá-los.

Primeiro, precisamos classificar as funções que retornam valores de relógio de parede e comparar as funções que retornam valores de processos ou threads . gettimeofdayretornos valor parede do relógio, clock_gettimeretorna valor relógio de parede ou de processo ou valores de fios dependendo do Clockparâmetro transmitido ao mesmo. getrusagee clockretornar valores do processo.

Em seguida, a segunda pergunta diz respeito à implementação dessas funções e, como conseqüência, à sua precisão. Qual mecanismo de hardware ou software essas funções usam.

Parece que getrusageusa apenas o tick do kernel (geralmente 1ms de comprimento) e, como conseqüência, não pode ser mais preciso que o ms. Está certo? Em seguida, a getimeofdayfunção parece usar o hardware subjacente mais preciso disponível. Como conseqüência, sua precisão é geralmente o microssegundo (não pode ser mais por causa da API) no hardware recente. E clocka página de manual fala sobre "aproximação", o que isso significa? E clock_gettimea API está em nanossegundos? Isso significa que ela pode ser tão precisa se o hardware subjacente permitir? E a monotonicidade?

Existem outras funções?

Manuel Selva
fonte

Respostas:

198

O problema é que existem várias funções de tempo diferentes disponíveis em C e C ++, e algumas delas variam de comportamento entre implementações. Também existem muitas meias-respostas flutuando. Compilar uma lista de funções do relógio junto com suas propriedades responderia à pergunta corretamente. Para começar, vamos perguntar quais são as propriedades relevantes que estamos procurando. Olhando para a sua postagem, sugiro:

  • Que horas são medidas pelo relógio? (real, usuário, sistema ou, espero que não, relógio de parede?)
  • Qual é a precisão do relógio? (s, ms, µs ou mais rápido?)
  • Depois de quanto tempo o relógio volta? Ou existe algum mecanismo para evitar isso?
  • O relógio é monotônico ou mudará com as alterações na hora do sistema (via NTP, fuso horário, horário de verão, pelo usuário etc.)?
  • Como o acima varia entre implementações?
  • A função específica é obsoleta, fora do padrão etc.?

Antes de iniciar a lista, gostaria de salientar que o horário do relógio de parede raramente é o horário certo a ser usado, ao passo que muda com as alterações de fuso horário, o horário de verão ou se o relógio de parede é sincronizado pelo NTP. Nenhuma dessas coisas é boa se você estiver usando o tempo para agendar eventos ou avaliar o desempenho. É realmente muito bom para o que o nome diz, um relógio na parede (ou na mesa).

Aqui está o que eu encontrei até agora para relógios no Linux e OS X:

  • time() retorna a hora do relógio do sistema operacional, com precisão em segundos.
  • clock()parece retornar a soma do tempo do usuário e do sistema. Está presente no C89 e posterior. Ao mesmo tempo, esse era o tempo da CPU em ciclos, mas padrões modernos como o POSIX exigem que CLOCKS_PER_SEC seja 1000000, fornecendo a máxima precisão possível de 1 µs. A precisão no meu sistema é de fato 1 µs. Esse relógio gira em torno de uma vez que termina (normalmente ocorre após ~ 2 ^ 32 tiques, o que não é muito longo para um relógio de 1 MHz). man clockdiz que desde o glibc 2.18 ele é implementado clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)no Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...)fornece resolução de nanossegundos, é monotônico. Acredito que os 'segundos' e os 'nanossegundos' são armazenados separadamente, cada um em contadores de 32 bits. Assim, qualquer quebra ocorreria após várias dezenas de anos de atividade. Parece um relógio muito bom, mas infelizmente ainda não está disponível no OS X. O POSIX 7 descreve CLOCK_MONOTONICcomo uma extensão opcional .
  • getrusage()acabou por ser a melhor escolha para a minha situação. Ele relata as horas do usuário e do sistema separadamente e não é contornado. A precisão no meu sistema é de 1 µs, mas também testei em um sistema Linux (Red Hat 4.1.2-48 com GCC 4.1.2) e a precisão era de apenas 1 ms.
  • gettimeofday()retorna a hora do relógio de parede com (nominalmente) µs de precisão. No meu sistema, esse relógio parece ter precisão de µs, mas isso não é garantido, porque "a resolução do relógio do sistema depende do hardware" . O POSIX.1-2008 diz isso . "Os aplicativos devem usar a clock_gettime()função em vez da gettimeofday()função obsoleta ", portanto, você deve ficar longe dela. Linux x86 e implementa-o como uma chamada de sistema .
  • mach_absolute_time()é uma opção para temporização de resolução muito alta (ns) no OS X. No meu sistema, isso realmente dá uma resolução ns. Em princípio, esse relógio gira em torno de, no entanto, ele está armazenando ns usando um número inteiro não assinado de 64 bits; portanto, o acondicionamento não deve ser um problema na prática. Portabilidade é questionável.
  • Eu escrevi uma função híbrida baseada nesse trecho que usa clock_gettime quando compilado no Linux, ou um temporizador Mach quando compilado no OS X, para obter precisão ns no Linux e no OS X.

Todos os itens acima existem no Linux e no OS X, exceto onde especificado em contrário. "Meu sistema" acima é um Apple executando o OS X 10.8.3 com GCC 4.7.2 do MacPorts.

Finalmente, aqui está uma lista de referências que eu achei úteis, além dos links acima:


Atualização : para OS X, clock_gettimefoi implementada a partir da 10.12 (Sierra). Além disso, as plataformas baseadas em POSIX e BSD (como OS X) compartilham o rusage.ru_utimecampo struct.

Douglas B. Staple
fonte
O Mac OS X não tem clock_gettime, portanto, o uso de gettimeofday()ser um pouco mais versátil do queclock_gettime()
bobobobo
1
Você não mencionou times()(com s), que existe no POSIX desde a edição 1. Sobre o GNU / Linux: De acordo com a página do manual clock (3), o clock()glibc 2.17 e versões anteriores foram implementadas por cima, mas para melhorias precisão, agora é implementado no topo clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...), o que também é especificado no POSIX, mas é opcional.
precisa saber é
2
@starflyer A precisão do relógio é parcialmente limitada pela quantidade de tempo que leva para pesquisar o relógio. Isso ocorre porque, se eu ligar para o relógio e levar 1 µs para retornar, a hora em que o relógio será "desligado" em 1 µs da perspectiva do chamador. Isso significa que um relógio altamente preciso também deve ser de baixa latência. Portanto, normalmente não se tem o compromisso que você está falando: os relógios mais baratos também serão os mais precisos.
Douglas B. Staple
3
Além disso, a maioria dos relógios não se preocupa com o horário de verão / fuso horário, mesmo que sejam considerados relógios de parede . Ambos timee gettimeofdayretornam, pelo menos hoje em dia, segundos desde a época (aka unix-timestamps). Isso é independente dos fusos horários / horário de verão. Bissextos segundos são outra história ...
Zulan
2
Para usuários do Android, o uso do CLOCK_MONOTONIC pode ser problemático, pois o aplicativo pode ser suspenso junto com o relógio. Para isso, o Android adicionou o cronômetro ANDROID_ALARM_ELAPSED_REALTIME, acessível através do ioctl. algumas informações sobre estes e outros suspender informações relacionadas podem ser encontradas aqui
Itay Bianco
17

C11 timespec_get

Exemplo de uso em: https://stackoverflow.com/a/36095407/895245

A precisão máxima possível retornada é de nanossegundos, mas a precisão real é definida pela implementação e pode ser menor.

Ele retorna o tempo de espera, não o uso da CPU.

O glibc 2.21 o implementa abaixo sysdeps/posix/timespec_get.ce encaminha diretamente para:

clock_gettime (CLOCK_REALTIME, ts) < 0)

clock_gettimee CLOCK_REALTIMEsão POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html , e man clock_gettimeafirma que esta medida pode ter descontinuidades se você alterar alguma configuração de hora do sistema enquanto o programa é executado.

C ++ 11 crono

Como estamos nisso, vamos abordá-los também: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (C ++ stdlib está dentro da origem do GCC):

  • high_resolution_clock é um apelido para system_clock
  • system_clock encaminha para o primeiro dos seguintes itens disponíveis:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock encaminha para o primeiro dos seguintes itens disponíveis:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Perguntado em: Diferença entre std :: system_clock e std :: stable_clock?

CLOCK_REALTIMEvs CLOCK_MONOTONIC: Diferença entre CLOCK_REALTIME e CLOCK_MONOTONIC?

Ciro Santilli adicionou uma nova foto
fonte
1
Ótima resposta que desmistifica as implementações típicas. É o que as pessoas realmente precisam saber.
Celess