Comment mesurer un intervalle de temps en C?

Je voudrais mesurer le temps en C, et j’ai du mal à le comprendre, tout ce que je veux, c’est quelque chose comme ceci:

  • démarrer une timer
  • exécuter une méthode
  • arrêter la timer
  • signaler le temps nécessaire (au moins à la précision micro)

Toute aide serait appréciée.

(Je comstack dans windows en utilisant mingw)

Les timers haute résolution fournissant une résolution de 1 microseconde sont spécifiques au système, vous devrez donc utiliser différentes méthodes pour y parvenir sur différentes plates-formes de système d’exploitation. Vous pourriez être intéressé par l’article suivant, qui implémente une classe d’horloge C ++ multi-plateforme basée sur les fonctions décrites ci-dessous:

  • Song Ho Ahn – Minuterie haute résolution

les fenêtres

L’API Windows fournit des fonctions de timer à très haute résolution: QueryPerformanceCounter() , qui renvoie les ticks actuels et QueryPerformanceFrequency() , qui renvoie le nombre de ticks par seconde.

Exemple:

 #include  #include  // 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 et Mac

Pour un système basé sur Unix ou Linux, vous pouvez utiliser gettimeofday() . Cette fonction est déclarée dans "sys / time.h".

Exemple:

 #include  #include  // 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; } 

Notez que les exemples ci-dessus doivent être compilés avec C ++, supporté par mingw .

Sous Linux, vous pouvez utiliser 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 

Ce qui suit est un groupe de fonctions C polyvalentes pour la gestion des temporisateurs basé sur l’appel système gettimeofday (). Toutes les propriétés du minuteur sont contenues dans une structure unique ticktimer – l’intervalle souhaité, le temps total écoulé depuis l’initialisation du minuteur, un pointeur sur le rappel que vous souhaitez appeler, le nombre de fois que le rappel a été appelé. Une fonction de rappel ressemblerait à ceci:

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

Pour initialiser et démarrer un temporisateur, appelez ticktimer_init (your_timer, interval, TICKTIMER_RUN, your_timer_cb, 0).

Dans la boucle principale de votre programme, appelez ticktimer_tick (your_timer) et il décidera si le délai approprié a été utilisé pour appeler le rappel.

Pour arrêter une timer, appelez simplement ticktimer_ctl (your_timer, TICKTIMER_STOP).

ticktimer.h:

 #ifndef __TICKTIMER_H #define __TICKTIMER_H #include  #include  #include  #include  #include  #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); } } } 

Voici un fichier d’en-tête que j’ai écrit pour réaliser des profils de performances simples (à l’aide de timers manuelles):

 #ifndef __ZENTIMER_H__ #define __ZENTIMER_H__ #ifdef ENABLE_ZENTIMER #include  #ifdef WIN32 #include  #else #include  #endif #ifdef HAVE_STDINT_H #include  #elif HAVE_INTTYPES_H #include  #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__ */ 

La fonction ztime() est la logique principale dont vous avez besoin – elle obtient l’heure actuelle et la stocke dans une valeur de 64 bits mesurée en microsecondes. Vous pouvez ensuite faire des calculs simples pour connaître le temps écoulé.

Les fonctions ZenTimer*() ne sont que des fonctions d’assistance pour amener un pointeur sur une structure de temporisation simple, ztimer_t , qui enregistre l’heure de début et l’heure de fin. Les fonctions ZenTimerPause() / ZenTimerResume() vous permettent, par exemple, de suspendre et de reprendre le minuteur si vous souhaitez imprimer des informations de débogage que vous ne souhaitez pas chronométrer.

Vous pouvez trouver une copie du fichier d’en-tête original à l’ adresse http://www.gnome.org/~fejj/code/zentimer.h si j’ai perdu le code HTML d’échapper à

Voici une solution pour GNU / Linux qui utilise le compteur d’horodatage du processeur x86:

  • Mise en garde: Fonctionne uniquement sur les kernelx x86 et les kernelx sans tiques …
  • Anecdote: qui peut nous dire quel est le timing retourné sur un kernel sans tic-tac?
  • Astuce: ce ne sera pas en temps réel

rdtsc.c:

 #include  #include  #include  #include  #include  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; } 

comstackr et exécuter avec

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

Il lit le diviseur correct pour votre CPU à partir de / proc / cpuinfo et montre combien de temps il a fallu pour le lire en microsecondes, ainsi que le temps d'exécution de sleep (1) en millisecondes.

... En supposant que la cote Mhz dans / proc / cpuinfo contient toujours 3 décimales: -o

Jetez un coup d’oeil à celui-ci cependant si vous voulez un calcul précis, je pense que vous devez utiliser des bibliothèques spécifiques sur votre système d’exploitation.

En utilisant la bibliothèque time.h, essayez quelque chose comme ceci:

 long start_time, end_time, elapsed; start_time = clock(); // Do something end_time = clock(); elapsed = (end_time - start_time) / CLOCKS_PER_SEC * 1000; 

Si votre système Linux le prend en charge, clock_gettime (CLOCK_MONOTONIC) doit être un minuteur haute résolution non affecté par les modifications de date du système (par exemple, les démons NTP).