2012-01-28 8 views
5

Estoy tratando de medir intervalos de tiempo cortos, en orden de pocos milisegundos. Esto demuestra ser una tarea no trivial, ya que la función omnipresente time() funciona con precisión de segundos enteros. Después de algunas investigaciones Salí con los cuatro métodos visto en el ejemplo de código a continuación:Medición de intervalos de tiempo cortos en C en Ubuntu/VMware

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

int main(int argc, char *argv[]) 
{ 
    clock_t t0, t1; 
    double dt0; 

    struct timespec t2, t3; 
    double dt1; 

    struct timespec t4, t5; 
    double dt2; 

    struct timeval t6, t7; 
    double dt3; 

    volatile long long i; 

    t2.tv_sec = 0; 
    t2.tv_nsec = 0; 
    clock_settime(CLOCK_MONOTONIC, &t2); 
    clock_settime(CLOCK_REALTIME, &t2); 

    t0 = clock(); 
    clock_gettime(CLOCK_REALTIME, &t2); 
    clock_gettime(CLOCK_MONOTONIC, &t4); 
    gettimeofday(&t6, NULL); 

    getchar(); 
    for (i=0; i<1e9; i++) {}; 

    gettimeofday(&t7, NULL); 
    clock_gettime(CLOCK_MONOTONIC, &t5); 
    clock_gettime(CLOCK_REALTIME, &t3); 
    t1 = clock(); 

    dt0 = (double) (t1 - t0)/CLOCKS_PER_SEC; 
    dt1 = (double) (t3.tv_nsec - t2.tv_nsec)/1e9; 
    dt2 = (double) (t5.tv_nsec - t4.tv_nsec)/1e9; 
    dt3 = (double) (t7.tv_usec - t6.tv_usec)/1e6; 

    printf("1. clock():   [0]=%10.0f, [1]=%10.0f, [1-0]=%10.6f sec\n", (double) t0, (double) t1, dt0); 
    printf("2. clock_gettime(R): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t2.tv_nsec, (long) t3.tv_nsec, dt1); 
    printf("3. clock_gettime(M): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t4.tv_nsec, (long) t5.tv_nsec, dt2); 
    printf("4. gettimeofday(): [4]=%10ld, [5]=%10ld, [5-4]=%10f sec\n", (long) t6.tv_usec, (long) t7.tv_usec, dt3); 

    return 0; 
} 

Entonces, compilada y ejecutada con:

gcc -lrt -o timer.e timer.c; time ./timer.e 

que utiliza la llamada getchar() a introducir un par de retraso segundos para ver una diferencia entre real y user informes de tiempo, y el resultado fue:

1. clock():   [0]=   0, [1]= 3280000, [1-0]= 3.280000 sec 
2. clock_gettime(R): [2]= 823922476, [3]= 478650549, [3-2]= -0.345272 sec 
3. clock_gettime(M): [2]= 671137949, [3]= 325864897, [3-2]= -0.345273 sec 
4. gettimeofday(): [4]= 823924, [5]= 478648, [5-4]= -0.345276 sec 

real 0m6.659s 
user 0m3.280s 
sys  0m0.010s 

Como se puede ver, el único el resultado significativo es la correlación entre el método 1 y el user tiempo informado por el comando time.

Esto trae un par de preguntas: 1. ¿Por qué los resultados 2-4 no tienen sentido? 2. ¿Cómo mido el tiempo real dedicado a ejecutar un programa, como el real número time informes?

Mi entorno es Ubuntu 10.04 LTS de 64 bits en VMware en Windows 7 en una computadora portátil HP basada en AMD.

+0

Si esto es para propósitos de prueba, puede que le resulte útil para aumentar el número de iteraciones. Esto, por supuesto, hará que la prueba se ejecute más tiempo, pero puede hacer uso de mediciones de tiempo de resolución más baja. –

+0

@MichaelMior: se usa para comparaciones muy aproximadas. Estoy tratando de comparar el tiempo de ejecución de algún algoritmo que se ejecuta en el host (Linux) y en un acelerador de hardware que está conectado a través de USB. En ambos casos, la persona que llama es el mismo programa, el programa host, y necesito una manera de obtener el tiempo total que simplemente "espera y espera" para que el hardware externo finalice su trabajo. Esta es la razón por la cual clock() no es la respuesta, b/c no cuenta para el tiempo de espera (como lo demuestra la llamada getchar()). – ysap

Respuesta

12

Estás en el camino correcto con clock_gettime().

Sin embargo, debe deshacerse de esas llamadas clock_settime(): simplemente llame al clock_gettime() antes y después de un bloque de código, y observe la diferencia.

Además, al calcular la diferencia, debe tener en cuenta tv_sec y tv_nsec; su código actual solo mira el componente nanosegundo e ignora los segundos completos.

En mi sistema Ubuntu el siguiente código da una medida bastante precisa del tiempo que se tarda en ejecutar el bucle:

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

int main(int argc, char *argv[]) 
{ 
    struct timespec t2, t3; 
    double dt1; 

    volatile long long i; 

    clock_gettime(CLOCK_MONOTONIC, &t2); 
    for (i=0; i<1e9; i++) {}; 
    clock_gettime(CLOCK_MONOTONIC, &t3); 
    //time in seconds 
    dt1 = (t3.tv_sec - t2.tv_sec) + (double) (t3.tv_nsec - t2.tv_nsec) * 1e-9; 
    printf("%f\n", dt1); 

    return 0; 
} 
+0

¡Gracias! Esta corrección hace lo que estoy buscando. De vez en cuando uno echa de menos ver lo obvio. Pensé que los campos _sec y _nsec lastiman los mismos datos con diferente precisión, pero ahora veo que son las partes completas y nanosecas de la marca de tiempo. – ysap

1

algún indicio acerca de la medición del tiempo hasta micro segundos e incluso nano http://en.wikipedia.org/wiki/Time_Stamp_Counter

+0

Gracias por señalar una explicación en rdtsc. Puede ser útil en algunos contextos, pero estoy tratando de descubrir por qué el código que escribí no da el resultado esperado. – ysap

1

Tus llamadas clock_settime no hacen lo que crees que hacen. Si tuviera el permiso, simplemente configuraría el reloj del sistema en 0, probablemente no lo que desea. Casi todas las funciones POSIX tienen un valor de retorno que le dice si la llamada tuvo éxito. Por lo general, es una mala idea ignorar ese valor. Para su caso en particular, creo que debería haber dado este valor, ya que se puede encontrar en la página man:

clock_settime EPERM() no tiene permiso para configurar el reloj indicado.

suerte que no tienen los permisos para ajustar el reloj tan simple como esto :)

+0

Agregué el tiempo de configuración después de recibir los resultados extraños de gettime. Aparentemente, no tuvo ningún efecto en el resultado. – ysap

+0

@ysap, esto es exactamente lo que estoy diciendo. No tiene ningún efecto en el resultado ya que ** falla **. De lo contrario, tendría consecuencias dramáticas para su máquina, configurando el reloj de su sistema a algo así como el 1 de enero de 1970, más o menos. No hagas eso. Verifique el retorno de las llamadas al sistema para ver si tienen éxito o no. –

+0

Sí, señalado y el código fue eliminado del programa. – ysap

Cuestiones relacionadas