2010-01-27 19 views
41

me gustaría medir el tiempo en C, y estoy teniendo un momento difícil averiguarlo, todo lo que quiero es algo como esto:¿Cómo mido un intervalo de tiempo en C?

  • iniciar un temporizador
  • ejecutar un método
  • detener la temporizador
  • informe
  • el tiempo necesario (por lo menos a la exactitud micro)

sería apreciada Cualquier ayuda.

(soy compilar en Windows utilizando MinGW)

+0

fecha-hora o tiempo de CPU? para este último, ver, por ejemplo, http://stackoverflow.com/questions/1380136/fast-elapsed-time-on-linux/1380663#1380663 – Christoph

Respuesta

88

Los temporizadores de alta resolución que proporcionan una resolución de 1 microsegundo son específicos del sistema, por lo que tendrá que usar diferentes métodos para lograr esto en diferentes plataformas de sistema operativo. Usted puede estar interesado en probar el siguiente artículo, que implementa una multiplataforma clase de C++ temporizador basado en las funciones que se describen a continuación:


de Windows

La API de Windows proporciona funciones de temporizador de resolución extremadamente alta: QueryPerformanceCounter(), que devuelve los tics transcurridos actuales, y QueryPerformanceFrequency(), wh Ich devuelve el número de tics por segundo.

Ejemplo:

#include <iostream> 
#include <windows.h>    // for Windows APIs 
using namespace std; 

int main() 
{ 
    LARGE_INTEGER frequency;  // ticks per second 
    LARGE_INTEGER t1, t2;   // ticks 
    double elapsedTime; 

    // get ticks per second 
    QueryPerformanceFrequency(&frequency); 

    // start timer 
    QueryPerformanceCounter(&t1); 

    // do something 
    // ... 

    // stop timer 
    QueryPerformanceCounter(&t2); 

    // compute and print the elapsed time in millisec 
    elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0/frequency.QuadPart; 
    cout << elapsedTime << " ms.\n"; 

    return 0; 
} 

Linux, Unix y Mac

Para el sistema basado en Unix o Linux, puede utilizar gettimeofday(). Esta función se declara en "sys/time.h".

Ejemplo:

#include <iostream> 
#include <sys/time.h>    // for gettimeofday() 
using namespace std; 

int main() 
{ 
    struct timeval t1, t2; 
    double elapsedTime; 

    // start timer 
    gettimeofday(&t1, NULL); 

    // do something 
    // ... 

    // stop timer 
    gettimeofday(&t2, NULL); 

    // compute and print the elapsed time in millisec 
    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;  // sec to ms 
    elapsedTime += (t2.tv_usec - t1.tv_usec)/1000.0; // us to ms 
    cout << elapsedTime << " ms.\n"; 

    return 0; 
} 

Tenga en cuenta que los ejemplos anteriores necesitan ser compilado con C++, que mingw soportes.

+7

Creo que debería ser struct timeval, no solo timeval. – rightaway717

+1

'struct timeval' funcionó para mí (algunos GCC ARM compilador) – Micka

+0

En Android informa un valor extrañamente grande. Cuando t2.tv_usec = 925311 y t1.tv_usec = 861102, elapsedTime se informa como 262144000. Esto es después de agregar "struct" como se menciona rightaway717. – Nicholas

0

Tome un lok en this one sin embargo si quieres cálculo preciso que creo que hay que utilizar bibliotecas específicas de su sistema operativo.

+0

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales del responda aquí y proporcione el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. –

0

El uso de la biblioteca time.h, intentar algo como esto:

long start_time, end_time, elapsed; 

start_time = clock(); 
// Do something 
end_time = clock(); 

elapsed = (end_time - start_time)/CLOCKS_PER_SEC * 1000; 
+0

'CLK_TCK' está obsoleto; use 'CLOCKS_PER_SEC' en su lugar – Christoph

+0

¡Correcto! Editado ¡Gracias! – Aaron

+3

'clock()' no alcanza una resolución de 1 microsegundo. Una fuente indica que su resolución es de aproximadamente 15 ms: http://www.songho.ca/misc/timer/timer.html –

2

Aquí es un archivo de cabecera que escribí que hacer algunos simples perfiles de rendimiento (utilizando temporizadores manuales):

#ifndef __ZENTIMER_H__ 
#define __ZENTIMER_H__ 

#ifdef ENABLE_ZENTIMER 

#include <stdio.h> 
#ifdef WIN32 
#include <windows.h> 
#else 
#include <sys/time.h> 
#endif 
#ifdef HAVE_STDINT_H 
#include <stdint.h> 
#elif HAVE_INTTYPES_H 
#include <inttypes.h> 
#else 
typedef unsigned char uint8_t; 
typedef unsigned long int uint32_t; 
typedef unsigned long long uint64_t; 
#endif 

#ifdef __cplusplus 
extern "C" { 
#pragma } 
#endif /* __cplusplus */ 

#define ZTIME_USEC_PER_SEC 1000000 

/* ztime_t represents usec */ 
typedef uint64_t ztime_t; 

#ifdef WIN32 
static uint64_t ztimer_freq = 0; 
#endif 

static void 
ztime (ztime_t *ztimep) 
{ 
#ifdef WIN32 
    QueryPerformanceCounter ((LARGE_INTEGER *) ztimep); 
#else 
    struct timeval tv; 

    gettimeofday (&tv, NULL); 

    *ztimep = ((uint64_t) tv.tv_sec * ZTIME_USEC_PER_SEC) + tv.tv_usec; 
#endif 
} 

enum { 
    ZTIMER_INACTIVE = 0, 
    ZTIMER_ACTIVE = (1 << 0), 
    ZTIMER_PAUSED = (1 << 1), 
}; 

typedef struct { 
    ztime_t start; 
    ztime_t stop; 
    int state; 
} ztimer_t; 

#define ZTIMER_INITIALIZER { 0, 0, 0 } 

/* default timer */ 
static ztimer_t __ztimer = ZTIMER_INITIALIZER; 

static void 
ZenTimerStart (ztimer_t *ztimer) 
{ 
    ztimer = ztimer ? ztimer : &__ztimer; 

    ztimer->state = ZTIMER_ACTIVE; 
    ztime (&ztimer->start); 
} 

static void 
ZenTimerStop (ztimer_t *ztimer) 
{ 
    ztimer = ztimer ? ztimer : &__ztimer; 

    ztime (&ztimer->stop); 
    ztimer->state = ZTIMER_INACTIVE; 
} 

static void 
ZenTimerPause (ztimer_t *ztimer) 
{ 
    ztimer = ztimer ? ztimer : &__ztimer; 

    ztime (&ztimer->stop); 
    ztimer->state |= ZTIMER_PAUSED; 
} 

static void 
ZenTimerResume (ztimer_t *ztimer) 
{ 
    ztime_t now, delta; 

    ztimer = ztimer ? ztimer : &__ztimer; 

    /* unpause */ 
    ztimer->state &= ~ZTIMER_PAUSED; 

    ztime (&now); 

    /* calculate time since paused */ 
    delta = now - ztimer->stop; 

    /* adjust start time to account for time elapsed since paused */ 
    ztimer->start += delta; 
} 

static double 
ZenTimerElapsed (ztimer_t *ztimer, uint64_t *usec) 
{ 
#ifdef WIN32 
    static uint64_t freq = 0; 
    ztime_t delta, stop; 

    if (freq == 0) 
     QueryPerformanceFrequency ((LARGE_INTEGER *) &freq); 
#else 
#define freq ZTIME_USEC_PER_SEC 
    ztime_t delta, stop; 
#endif 

    ztimer = ztimer ? ztimer : &__ztimer; 

    if (ztimer->state != ZTIMER_ACTIVE) 
     stop = ztimer->stop; 
    else 
     ztime (&stop); 

    delta = stop - ztimer->start; 

    if (usec != NULL) 
     *usec = (uint64_t) (delta * ((double) ZTIME_USEC_PER_SEC/(double) freq)); 

    return (double) delta/(double) freq; 
} 

static void 
ZenTimerReport (ztimer_t *ztimer, const char *oper) 
{ 
    fprintf (stderr, "ZenTimer: %s took %.6f seconds\n", oper, ZenTimerElapsed (ztimer, NULL)); 
} 

#ifdef __cplusplus 
} 
#endif /* __cplusplus */ 

#else /* ! ENABLE_ZENTIMER */ 

#define ZenTimerStart(ztimerp) 
#define ZenTimerStop(ztimerp) 
#define ZenTimerPause(ztimerp) 
#define ZenTimerResume(ztimerp) 
#define ZenTimerElapsed(ztimerp, usec) 
#define ZenTimerReport(ztimerp, oper) 

#endif /* ENABLE_ZENTIMER */ 

#endif /* __ZENTIMER_H__ */ 

El ztime() la función es la lógica principal que necesita: obtiene la hora actual y la almacena en un mensaje de 64 bits medido en microsegundos. Luego puede hacer cálculos simples para averiguar el tiempo transcurrido.

Las funciones ZenTimer*() son solo funciones auxiliares para tomar un puntero a una estructura de temporizador simple, ztimer_t, que registra la hora de inicio y la hora de finalización. Las funciones ZenTimerPause()/ZenTimerResume() le permiten, bueno, pausar y reanudar el temporizador en caso de que desee imprimir alguna información de depuración que no desee sincronizar, por ejemplo.

Puede encontrar una copia del archivo de encabezado original en http://www.gnome.org/~fejj/code/zentimer.h en caso de que estropee el escape html de < 's o algo así. Está licenciado bajo MIT/X11, así que siéntete libre de copiarlo en cualquier proyecto que hagas.

0

Si su sistema Linux lo admite, clock_gettime (CLOCK_MONOTONIC) debe ser un temporizador de alta resolución que no se vea afectado por los cambios de fecha del sistema (por ejemplo, demonios NTP).

+0

Dijo que está usando mingw en windows not linux – Shedokan

16

En Linux se puede utilizar clock_gettime():

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); // get initial time-stamp 

// ... do stuff ... // 

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); // get final time-stamp 

double t_ns = (double)(end.tv_sec - start.tv_sec) * 1.0e9 + 
       (double)(end.tv_nsec - start.tv_nsec); 
               // subtract time-stamps and 
               // multiply to get elapsed 
               // time in ns 
+0

sería bueno si pudieras explicar cómo funciona esto. – fireant

+0

¿Por qué votar abajo? Consulte: http://linux.die.net/man/3/clock_gettime para obtener más información sobre clock_gettime. –

2

El siguiente es un grupo de funciones C versátiles para la gestión de temporizador basado en la llamada al sistema gettimeofday(). Todas las propiedades del temporizador están contenidas en una sola estructura ticktimer: el intervalo que desea, el tiempo de ejecución total desde la inicialización del temporizador, un puntero a la devolución de llamada deseada a la que desea llamar, la cantidad de veces que se llamó a la devolución de llamada. Una función de devolución de llamada se vería así:

void your_timer_cb (struct ticktimer *t) { 
    /* do your stuff here */ 
} 

Para inicializar e iniciar un temporizador, llame ticktimer_init (your_timer, intervalo, TICKTIMER_RUN, your_timer_cb, 0).

En el ciclo principal de su programa, llame a ticktimer_tick (su_timer) y decidirá si ha transcurrido el tiempo apropiado para invocar la devolución de llamada.

Para detener un temporizador, simplemente llame a ticktimer_ctl (your_timer, TICKTIMER_STOP).

ticktimer.h:

#ifndef __TICKTIMER_H 
#define __TICKTIMER_H 

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

#define TICKTIMER_STOP   0x00 
#define TICKTIMER_UNCOMPENSATE 0x00 
#define TICKTIMER_RUN   0x01 
#define TICKTIMER_COMPENSATE 0x02 

struct ticktimer { 
    u_int64_t tm_tick_interval; 
    u_int64_t tm_last_ticked; 
    u_int64_t tm_total; 
    unsigned ticks_total; 
    void (*tick)(struct ticktimer *); 
    unsigned char flags; 
    int id; 
}; 

void ticktimer_init (struct ticktimer *, u_int64_t, unsigned char, void (*)(struct ticktimer *), int); 
unsigned ticktimer_tick (struct ticktimer *); 
void ticktimer_ctl (struct ticktimer *, unsigned char); 
struct ticktimer *ticktimer_alloc (void); 
void ticktimer_free (struct ticktimer *); 
void ticktimer_tick_all (void); 

#endif 

ticktimer.c:

#include "ticktimer.h" 

#define TIMER_COUNT 100 

static struct ticktimer timers[TIMER_COUNT]; 
static struct timeval tm; 

/*! 
    @brief 
    Initializes/sets the ticktimer struct. 

    @param timer 
    Pointer to ticktimer struct. 
    @param interval 
    Ticking interval in microseconds. 
    @param flags 
    Flag bitmask. Use TICKTIMER_RUN | TICKTIMER_COMPENSATE 
    to start a compensating timer; TICKTIMER_RUN to start 
    a normal uncompensating timer. 
    @param tick 
    Ticking callback function. 
    @param id 
    Timer ID. Useful if you want to distinguish different 
    timers within the same callback function. 
*/ 
void ticktimer_init (struct ticktimer *timer, u_int64_t interval, unsigned char flags, void (*tick)(struct ticktimer *), int id) { 
    gettimeofday(&tm, NULL); 
    timer->tm_tick_interval = interval; 
    timer->tm_last_ticked = tm.tv_sec * 1000000 + tm.tv_usec; 
    timer->tm_total = 0; 
    timer->ticks_total = 0; 
    timer->tick = tick; 
    timer->flags = flags; 
    timer->id = id; 
} 

/*! 
    @brief 
    Checks the status of a ticktimer and performs a tick(s) if 
    necessary. 

    @param timer 
    Pointer to ticktimer struct. 

    @return 
    The number of times the timer was ticked. 
*/ 
unsigned ticktimer_tick (struct ticktimer *timer) { 
    register typeof(timer->tm_tick_interval) now; 
    register typeof(timer->ticks_total) nticks, i; 

    if (timer->flags & TICKTIMER_RUN) { 
    gettimeofday(&tm, NULL); 
    now = tm.tv_sec * 1000000 + tm.tv_usec; 

    if (now >= timer->tm_last_ticked + timer->tm_tick_interval) { 
     timer->tm_total += now - timer->tm_last_ticked; 

     if (timer->flags & TICKTIMER_COMPENSATE) { 
     nticks = (now - timer->tm_last_ticked)/timer->tm_tick_interval; 
     timer->tm_last_ticked = now - ((now - timer->tm_last_ticked) % timer->tm_tick_interval); 

     for (i = 0; i < nticks; i++) { 
      timer->tick(timer); 
      timer->ticks_total++; 

      if (timer->tick == NULL) { 
      break; 
      } 
     } 

     return nticks; 
     } else { 
     timer->tm_last_ticked = now; 
     timer->tick(timer); 
     timer->ticks_total++; 
     return 1; 
     } 
    } 
    } 

    return 0; 
} 

/*! 
    @brief 
    Controls the behaviour of a ticktimer. 

    @param timer 
    Pointer to ticktimer struct. 
    @param flags 
    Flag bitmask. 
*/ 
inline void ticktimer_ctl (struct ticktimer *timer, unsigned char flags) { 
    timer->flags = flags; 
} 

/*! 
    @brief 
    Allocates a ticktimer struct from an internal 
    statically allocated list. 

    @return 
    Pointer to the newly allocated ticktimer struct 
    or NULL when no more space is available. 
*/ 
struct ticktimer *ticktimer_alloc (void) { 
    register int i; 

    for (i = 0; i < TIMER_COUNT; i++) { 
    if (timers[i].tick == NULL) { 
     return timers + i; 
    } 
    } 

    return NULL; 
} 

/*! 
    @brief 
    Marks a previously allocated ticktimer struct as free. 

    @param timer 
    Pointer to ticktimer struct, usually returned by 
    ticktimer_alloc(). 
*/ 
inline void ticktimer_free (struct ticktimer *timer) { 
    timer->tick = NULL; 
} 

/*! 
    @brief 
    Checks the status of all allocated timers from the 
    internal list and performs ticks where necessary. 

    @note 
    Should be called in the main loop. 
*/ 
inline void ticktimer_tick_all (void) { 
    register int i; 

    for (i = 0; i < TIMER_COUNT; i++) { 
    if (timers[i].tick != NULL) { 
     ticktimer_tick(timers + i); 
    } 
    } 
} 
1

he aquí una solución para GNU/Linux que utiliza el contador de marca de tiempo de la CPU x86:

  • Advertencia: Sólo funciona en kernels x86 y no tickless ...
  • Trivia: ¿quién puede decirnos qué t ¿Iming regresado está en un kernel sin tick?
  • Consejo: no será en tiempo real

rdtsc.c:

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

typedef unsigned long long int64; 

static __inline__ int64 getticks(void) 
{ 
    unsigned a, d; 
    asm volatile("rdtsc" : "=a" (a), "=d" (d)); 
    return (((int64)a) | (((int64)d) << 32)); 
} 

int main(){ 

    int64 tick,tick1; 
    unsigned time=0,ut,mt; 

    // ut is the divisor to give microseconds 
    // mt gives milliseconds 

    FILE *pf; 
    int i,r,l,n=0; 
    char s[100]; 

    // time how long it takes to get the divisors, as a test 
    tick = getticks(); 

    // get the divisors - todo: for max performance this can 
    // output a new binary or library with these values hardcoded 
    // for the relevant CPU - a kind-of ludicrous notion considering 
    // that this will only work on x86 compatible cpus anyways where 
    // performance is the least of your issues... 
    // ... curse of the assembly coder ;-) 
    pf = fopen("/proc/cpuinfo","r"); 
    do { 
     r=fscanf(pf,"%s",&s[0]); 
     if (r<0) { 
     n=5; break; 
     } else if (n==0) { 
     if (strcmp("MHz",s)==0) n=1; 
     } else if (n==1) { 
     if (strcmp(":",s)==0) n=2; 
     } else if (n==2) { 
     n=3; 
     }; 
    } while (n<3); 
    fclose(pf); 

    l=strlen(s); 
    s[l-4]=s[l-3]; 
    s[l-3]=s[l-2]; 
    s[l-2]=s[l-1]; 
    s[l-1]=(char)0; 

    mt=atoi(s); 
    s[l-4]=(char)0; 
    ut=atoi(s); 

    printf("%s Mhz - ut = %u, mt = %u // hardcode these for your a CPU-specific binary ;-)\n",s,ut,mt); 

    tick1 = getticks(); 
    time = (unsigned)((tick1-tick)/ut); 
    printf("%u us\n",time); 

    // time the duration of sleep(1) - plus overheads ;-) 
    tick = getticks(); 

    sleep(1); 

    tick1 = getticks(); 
    time = (unsigned)((tick1-tick)/mt); 
    printf("%u ms\n",time); 

    return 0; 
} 

compilar y ejecutar con

$ gcc -o rdtsc.c RDTSC & &./ RDTSC

Se lee el divisor correcto para su CPU de/proc/cpuinfo y muestra el tiempo que tomó para leer que en microsegundos, así como el tiempo que se tarda en ejecutar el sueño (1) en milisegundos.

... Suponiendo que la calificación Mhz en/proc/cpuinfo siempre contiene 3 decimales: -o

+0

Todo: mira de dónde lo sacó/proc/cpuinfo ... pero creo que es el momento ... así que lo mejor es leerlo en un formato más directo desde donde lo guarde el kernel ... – dagelf

+0

Quién está interesado para actualizar esto para leer desde kernel directamente? http://lxr.linux.no/linux+v3.8.1/arch/x86/kernel/cpu/proc.c http://lxr.linux.no/linux+v3.8.1/drivers/cpufreq/cpufreq. C# L1217 - incluso podría hacer que funcione en dispositivos de escalado de frecuencia ... – dagelf

+0

http://lxr.linux.no/linux+v3.8.1/arch/x86/kernel/tsc.c#L959 – dagelf

Cuestiones relacionadas