logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

Lendo e medindo o tempo em C e C++

Existem vários motivos para um programa consultar o "horário da máquina". Os mais comuns são registrar a data e hora de um acontecimento ou ação do usuário (data de acesso à um arquivo, por exemplo) ou medir o intervalo entre dois momentos para saber o tempo que algo levou.

Em C e C++ existem diversas maneiras de ler uma representação numérica de um determinado instante no tempo, e cada uma tem seu uso e característica. Essa salada de funções e APIs existem porque usando C e/ou C++ você tem acesso à todas as camadas de abstração (ou não-abstração), desde o relógio da placa mãe, passando pela BIOS, pelas APIs do sistema operacional até as funções da runtime do C ou do boost::datetime. Nessa série de posts vamos ver as características de cada forma de ler o "horário da máquina".

Toda representação numérica de um instante no tempo é dada pela diferença entre o instante da medição e um instante tido como referência. Quando usamos uma data e hora no nosso calendário gregoriano, tomamos como referência a "data tradicional da encarnação de Jesus Cristo". Isso é uma referência. 26 de maio de 1980 é tradução de (instance referência) + (1980 anos) + (5 meses) + (26 dias). Passando essa data para qualquer pessoa/programa que use a mesma refererência, ela consigirá saber de que instante no tempo você está falando. É importante saber esse conceito porque em programação a referência muitas vezes é diferente da referência do calendário gregoriano (por motivos técnicos e não religiosos. Sem teorias da conspiracão, pelamordedeus).

Quando usamos uma data e hora "normal" (ou seja, do calendário), ainda temos outra variável na verificação do horário: o fuso e o horário de verão. O horário de Brasília (fuso de São Paulo, onde eu moro) é de -3 horas em relação ao horário GMT, que é tido como a referência mundial para os fusos (GMT é Greenwich Mean Time, horário de Greenwich na Inglaterra). O horário de verão não muda o fuso do país, mas adianta o horário em uma hora. Na prática, é como se São Paulo virasse GMT-2. O fuso é uma informação controlada pelo SO, e mudar o fuso pode causar mais problemas ainda. Os SOs tratam o horário de verão explicitamente. Quem cuida de sistemas de produção onde a data e hora é algo importante sabe o inferno que é quando começa ou quando termina o horário de verão.

Saindo da história e voltando para a programação, existem alguns fatores importantes para escolher qual sistema de medição usar. Um fator importante é se o instante referência é fixo ou não (calendário gregoriano x quantidade de segundos desde que a máquina foi ligada). O outro é a precisão da medição, geralmente em segundos ou menos. Se você precisa medir o tempo que leva para concatenar uma string, medir em segundos não vai adiantar nada (isso geralmente leva nanosegundos).

Resumindo o que precisamos saber para escolher que função ou API de tempo usar:

  • Referência: se é uma referência fixa (início do calendário gregoriano) ou uma referência relativa (hora de início da máquina ou de inicialização do sistema operacional)
  • Precisão do retorno. Não adiantar usar uma função que retorna a hora com precisão de segundos se vou fazer um cálculo de período que leva microsegundos.
  • Precisão de leitura. Existem funções que retornam em milisegundos, mas a precisão é menor que isso. A função GetTickCount da API Win32 retorna a quantidade de millisegundos desde o início do sistema, mas sempre em intervalos maiores do que 15ms. Ou seja, ele não consegue medir algo que leva menos do que 15ms
  • Performance. Algumas funções de leitura de hora são mais rápidas que outras. Se vocês faz isso dentro de um loop, isso faz diferença

Por exemplo, uma função com precisão baixa pode ser usada para medir o tempo de abandono do meu blog, já que faz muuuito tempo que eu não atualizo isso aqui :-)

O próximo post terá código. Não se preocupem, estou mais ansioso por isso do que vocês.

Em 17/11/2009 23:32, por Rodrigo Strauss


  
 
 
Comentários
Ricardo Bittencourt | website | em 17/11/2009 | #
O melhor método é usar o rdtsc, mas aí precisa tomar cuidado pra garantir que você está lendo sempre do mesmo core. Usar o rdtsc sem esse cuidado em máquinas multicore pode levar à erro.
Rodrigo Strauss | website | em 17/11/2009 | #
As limitações do rdtsc são muitas, ainda mais em um mundo multicore. Um bug na BIOS e você está ferrado. Além de não ser portável. Além da sintaxe do assembly inline dos compiladores ser diferente.

E ele é bom somente para medir performance, que nem sempre é o caso. As vezes você só quer mesmo o horário da máquina...
Rodrigo Pinho | em 20/11/2009 | #
segue um codigo que pega a hora com precisao de microsegundos desde EPOCH, seguindo a mesma interface presente nos sistemas posix.

#include <sys/timeb.h>
#include <windows.h>

// isso ja eh definido no winsock2.h.
typedef struct timeval {
long tv_sec;
long tv_usec;
}timeval;

int gettimeofday(struct timeval *tv, void *t)
{
static struct timeval stv;
static LONGLONG sct, tick;
static int initialized = -1;
LARGE_INTEGER startCount;
LARGE_INTEGER tickPerSec;
struct timeb tb;

LARGE_INTEGER count;
LONGLONG c;

if (initialized == -1) {
ftime(&tb);
stv.tv_sec = tb.time;
stv.tv_usec = tb.millitm * 1000;
if (QueryPerformanceFrequency(&tickPerSec) == FALSE) {
exit(1);
}
if (QueryPerformanceCounter(&startCount) == FALSE) {
exit(1);
}
sct = startCount.QuadPart; tick = tickPerSec.QuadPart;
initialized = 0;
}

if (!QueryPerformanceCounter(&count))
return -1;
c = count.QuadPart;
tv->tv_sec = stv.tv_sec + (long)((c - sct) / tick);
tv->tv_usec = stv.tv_usec + (long)(((c - sct) % tick) * 1000000 / tick);
if (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
return 0;
}

| em 10/12/2009 | #
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::