Publi

Cronometrando en C

cronometro
Puede que queramos hacer una comparativa de cuánto tarda nuestro código en ejecutarse, o que tengamos varios algoritmos y queramos saber cuál es el más rápido. O que estemos haciendo un programa que mida el tiempo de reacción de un usuario en una cierta tarea. Aquí vemos ejemplos con diferentes precisiones.

Minutos

Este método viene bien para ver el tiempo transcurrido en un proceso que puede durar varios minutos. Si algo tarda 20 minutos, suele darnos igual segundo arriba, segundo abajo.

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
int anterior;
anterior=time(NULL);
sleep(1);
printf("Transcurrido: %ld\n", time(NULL)-anterior);
}

Sí, simplemente es esto, pero no voy a hacer un post sólo para esto, vamos a crear una función que llamemos cuando queremos empezar a cronometrar y volvamos a llamar cuando queramos parar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <time.h>

int cronosec(int startstop)
{
  static int pre_time;

  if (startstop)
    pre_time=time(NULL);
  else
    return time(NULL)-pre_time;

  return 0;
}

int main(int argc, char *argv[])
{
  cronosec(0);
  sleep(1);
  printf("Transcurrido: %ld\n", cronosec(1));
}

Con cronosec cuando empezamos a cronometrar, pasamos el parámetro 0, y cuando queremos ver el tiempo transcurrido llamamos al parámetro 1.

Precisión de milisegundo y microsegundo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <unistd.h>
#include <sys/time.h>

long long cronomsec(int startstop)
{
  static long long pre_time;
  struct timeval tv;

  if (startstop)
    {
      gettimeofday(&tv, NULL);      
      pre_time=tv.tv_sec*1000+tv.tv_usec/1000;
    }
  else
    {      
      gettimeofday(&tv, NULL);      
      return tv.tv_sec*1000+tv.tv_usec/1000 - pre_time;
    }
    return 0;
}

long long cronousec(int startstop)
{
  static long long pre_time;
  struct timeval tv;

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

Las dos se usan igual que cronosec(), cronomsec() tiene precisión de milisegundos y cronousec() de microsegundos; si las observamos las dos son iguales, sólo que en una, como queremos contar milisegundos, multiplicamos los segundos por mil y dividimos microsegundos entre 1000 (struct timeval es capaz de devolvernos microsegundos también).
En cronousec sólo multiplicamos los segundos por 1000000 (un millón).

Nanosegundo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <time.h>

unsigned long long crononsec(int startstop)
{
  static unsigned long pre_time;
  static unsigned long pre_secs;
  struct timespec ts;

  if (startstop)
    {
      clock_gettime(CLOCK_MONOTONIC, &ts);
      pre_time=ts.tv_nsec;
      pre_secs=ts.tv_sec;
    }
  else
    {      
      clock_gettime(CLOCK_MONOTONIC, &ts);
      return (ts.tv_sec-pre_secs)*1000000000+ts.tv_nsec - pre_time;
    }

    return 0;
}

Con esta función, gracias a clock_gettime(), obtenemos precisión de nanosegundos. Utilizo CLOCK_MONOTONIC porque este reloj no cambia, es decir, existe la función clock_settime, y este reloj no se podrá cambiar, de hecho no queremos que nos hagan trampa en nuestras aplicaciones, cambien la hora del ordenador y nuestro programa no funcione bien. Si no, podemos usar CLOCK_REALTIME, aunque este se puede cambiar, aunque necesita privilegios.
En este último ejemplo, vemos que no multiplico los segundos desde el principio como hacía antes, ahora sólo acumulo segundos, y luego multiplico la diferencia; esto es, porque el número de segundos ya acontecidos desde 1970 (Epoch) es demasiado grande, y si lo multiplico por 1000000000 (mil millones) para saber cuántos microsegundos han pasado desde entonces, el número es demasiado grande y desborda la variable (mira que es long long y tiene 64bits), así que aplico este método, mucho más inteligente y menos costoso (dos multiplicaciones frente a una), también podía hacer todos los métodos anteriores así, aunque el precio de hacer menos operaciones es la reserva de una variable más.

Un ejemplo para probarlo todo

Una vez colocadas todas las funciones en un archivo .c y todos los includes correspondientes arriba, añadimos este main():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(int argc, char *argv[])
{
  cronosec(1);
  cronomsec(1);
  cronousec(1);
  crononsec(1);
  usleep(4123789);      /* 4 segundos y pico*/
  printf("segundos: %d\n", cronosec(0));
  printf("milisegundos: %lld\n", cronomsec(0));
  printf("microsegundos: %lld\n", cronousec(0));
  printf("nanosegundos: %llu\n", crononsec(0));
 
  return EXIT_SUCCESS;
}

Una advertencia, las funciones que tienen más precisión de segundos son dependientes de la plataforma, además, para compilarlos necesitamos añadir la librería rt al compilar, de la siguiente forma:

$ gcc -lrt -o crono crono.c

Foto: Bajo licencia de dominio público, descargada de (pixabay)

También podría interesarte...

There are 7 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Pingback: BlogESfera.com /

  3. Nikoi /
    Usando Google Chrome Google Chrome 8.0.552.215 en Windows Windows XP

    Gracias por el articulo ! Yo he usado estas funciones sobre todo cuando quiero medir tiempos de diferentes algoritmos. Tambien utilizo (aunque no simpre ,pero es interesante saberlo) esta tecnica para detectar memory leaks en mis programas . http://chkno.net/memory-profiler.html

  4. admin / Post Author
    Usando Mozilla Firefox Mozilla Firefox 3.6 en Linux Linux

    Muchas gracias por tu aportación. Me había topado con ese profiler alguna vez y la verdad es que está muy bien

  5. Pingback: Poesía binaria » Extraer 10 elementos ordenados de grandes colecciones de datos /

  6. Marcos S /
    Usando Mozilla Firefox Mozilla Firefox 11.0 en Ubuntu Linux Ubuntu Linux

    Gracias por el código, me fue útil para medir tiempos en una simulación.

    1. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 11.0 en Ubuntu Linux Ubuntu Linux

      Me alegro de que te haya sido útil !

Leave a Reply