Question

En utilisant seulement ANSI C, est-il possible de mesurer le temps avec précision millisecondes ou plus? Je regardais time.h mais je ne ai trouvé secondes fonctions de précision.

Était-ce utile?

La solution

Il n'y a pas de fonction ANSI C qui permet de mieux de 1 seconde résolution temporelle, mais la fonction POSIX

Autres conseils

#include <time.h>
clock_t uptime = clock() / (CLOCKS_PER_SEC / 1000);

J'utilise toujours la fonction clock_gettime (), le temps de retour de l'horloge CLOCK_MONOTONIC. Le temps de retour est le laps de temps, en secondes et nanosecondes, depuis un moment non précisé dans le passé, comme le démarrage du système de l'époque.

#include <stdio.h>
#include <stdint.h>
#include <time.h>

int64_t timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
  return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
           ((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}

int main(int argc, char **argv)
{
  struct timespec start, end;
  clock_gettime(CLOCK_MONOTONIC, &start);

  // Some code I am interested in measuring 

  clock_gettime(CLOCK_MONOTONIC, &end);

  uint64_t timeElapsed = timespecDiff(&end, &start);
}

Mise en oeuvre d'une solution portable

Comme on l'a déjà mentionné ici qu'il n'y a pas de solution ANSI appropriée avec suffisamment de précision pour le moment problème de mesure, je veux écrire sur les façons comment obtenir un portable et, si possible, une solution de mesure du temps à haute résolution.

Horloge Monotonic par rapport à l'horodatage

De façon générale, il y a deux façons de mesure du temps:

  • Horloge monotones;
  • actuelle (date) horodatage.

La première utilise un compteur d'horloge monotones (parfois il est appelé un compteur à cocher) qui compte les tiques avec une fréquence prédéfinie, donc si vous avez une valeur tiques et la fréquence est connue, vous pouvez facilement convertir les tiques en temps écoulé. Il est en fait pas garanti qu'une horloge monotones reflète l'heure du système actuel de quelque façon, il peut aussi compter les tiques depuis un démarrage du système. Mais il garantit qu'une horloge est toujours heurtons de façon croissante quel que soit l'état du système. En général, la fréquence est liée à un matériel source de haute résolution, c'est pourquoi il offre une grande précision (en fonction du matériel, mais la plupart du matériel moderne n'a pas de problèmes avec des sources d'horloge à haute résolution).

La deuxième façon fournit une valeur de temps (date) en fonction de la valeur d'horloge du système actuel. Il peut aussi avoir une haute résolution, mais il a un inconvénient majeur: ce genre de valeur temps peut être affectée par différents ajustements de temps du système, à savoir changement de fuseau horaire, l'heure d'été (DST) changement, mise à jour du serveur NTP, mise en veille prolongée du système et ainsi sur. Dans certaines circonstances, vous pouvez obtenir une valeur de temps écoulé négatif qui peut conduire à un comportement non défini. En fait, ce genre de source de temps est moins fiable que le premier.

La première règle dans l'intervalle de temps de mesure est d'utiliser une horloge monotones si possible. Il a généralement une grande précision, et il est fiable par la conception.

Stratégie Fallback

Lors de la mise en œuvre d'une solution portable, il vaut la peine d'envisager une stratégie de repli. Utiliser une horloge monotones si l'approche disponible et à fallback timbres de temps s'il n'y a pas d'horloge monotones dans le système

de Windows

Il y a un article intitulé l'acquisition de l'horodatage à haute résolution sur MSDN au sujet de la mesure du temps sur Windows qui décrit tous les détails dont vous avez besoin de savoir sur les logiciels et le support matériel. Pour acquérir un horodatage de haute précision sur Windows, vous devez:

  • interroger une fréquence d'horloge (tiques par seconde) avec QueryPerformanceFrequency :

    LARGE_INTEGER tcounter;
    LARGE_INTEGER freq;    
    
    if (QueryPerformanceFrequency (&tcounter) != 0)
        freq = tcounter.QuadPart;
    

    La fréquence d'horloge est fixé sur le démarrage du système afin que vous devez obtenir une seule fois.

  • interroger la valeur courante tiques avec QueryPerformanceCounter :

    LARGE_INTEGER tcounter;
    LARGE_INTEGER tick_value;
    
    if (QueryPerformanceCounter (&tcounter) != 0)
        tick_value = tcounter.QuadPart;
    
  • Echelle les tiques au temps écoulé, à savoir de microsecondes:

    LARGE_INTEGER usecs = (tick_value - prev_tick_value) / (freq / 1000000);
    

Selon Microsoft vous ne devriez pas avoir de problèmes avec cette approche sous Windows XP et les versions ultérieures dans la plupart des cas. Mais vous pouvez aussi utiliser deux solutions de secours sous Windows:

  • GetTickCount indique le nombre de millisecondes qui se sont écoulées depuis le système a été commencé. Elle enveloppe tous les 49,7 jours, alors faites attention à la mesure des intervalles plus longs.
  • GetTickCount64 est une version 64 bits de GetTickCount, mais il est disponible à partir de Windows Vista et au-dessus.

OS X (Mac OS)

OS X (MacOS) possède ses propres unités de temps absolu Mach laquelle Represent une horloge monotones. La meilleure façon de commencer est l'article et technique d'Apple qui décrit (avec les exemples de code) comment utiliser l'API spécifique à Mach pour obtenir les tiques monotones. Il y a aussi une question locale à ce sujet appelé alternative clock_gettime sous Mac OS X qui, à la fin peut vous laisser un peu confus quoi faire avec le trop-plein de valeur possible, car la fréquence du compteur est utilisé sous forme de numérateur et le dénominateur. Ainsi, un court exemple comment obtenir le temps écoulé:

  • obtenir le numérateur de fréquence d'horloge et le dénominateur:

    #include <mach/mach_time.h>
    #include <stdint.h>
    
    static uint64_t freq_num   = 0;
    static uint64_t freq_denom = 0;
    
    void init_clock_frequency ()
    {
        mach_timebase_info_data_t tb;
    
        if (mach_timebase_info (&tb) == KERN_SUCCESS && tb.denom != 0) {
            freq_num   = (uint64_t) tb.numer;
            freq_denom = (uint64_t) tb.denom;
        }
    }
    

    Vous devez faire une seule fois.

  • interroger la valeur de la tique courante avec mach_absolute_time:

    uint64_t tick_value = mach_absolute_time ();
    
  • Echelle les tiques au temps écoulé, à savoir de microsecondes, en utilisant le numérateur et le dénominateur précédemment demandées:

    uint64_t value_diff = tick_value - prev_tick_value;
    
    /* To prevent overflow */
    value_diff /= 1000;
    
    value_diff *= freq_num;
    value_diff /= freq_denom;
    

    L'idée principale pour éviter un débordement est de réduire les tiques à la précision souhaitée avant d'utiliser le numérateur et le dénominateur. Comme la résolution de la minuterie initiale est en nanosecondes, on divise par microsecondes pour obtenir 1000. Vous pouvez trouver la même approche utilisée dans le time_mac.c . Si vous avez vraiment besoin d'une précision de nanoseconde Comment puis-je utiliser mach_absolute_time sans déborder .

Linux et UNIX

L'appel est votre meilleur clock_gettime façon sur tout système convivial Posix. Il peut demander du temps à partir de différentes sources d'horloge, et celui que nous avons besoin est CLOCK_MONOTONIC. Tous les systèmes qui ont un soutien _POSIX_MONOTONIC_CLOCK >= 0, la première chose que vous devez faire est de vérifier sa disponibilité:

  • si 0 est définie à une valeur sysconf cela signifie que gettimeofday est disponibles;
  • si est défini à CLOCK_SGI_CYCLE cela signifie que gethrtime vous devez en outre vérifier si elle fonctionne à l'exécution, je vous suggère d'utiliser system_time:

    #include <unistd.h>
    
    #ifdef _SC_MONOTONIC_CLOCK
    if (sysconf (_SC_MONOTONIC_CLOCK) > 0) {
        /* A monotonic clock presents */
    }
    #endif
    
  • sinon une horloge monotonique pas pris en charge et vous devez utiliser une stratégie de repli (voir ci-dessous).

L'utilisation de DosTmrQueryFreq est assez simple:

  • obtenir la valeur du temps:

    #include <time.h>
    #include <sys/time.h>
    #include <stdint.h>
    
    uint64_t get_posix_clock_time ()
    {
        struct timespec ts;
    
        if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
            return (uint64_t) (ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
        else
            return 0;
    }
    

    Je l'ai mis à l'échelle sur le temps de microsecondes ici.

  • calculer la différence avec la valeur de temps précédent reçu de la même manière:

    uint64_t prev_time_value, time_value;
    uint64_t time_diff;
    
    /* Initial time */
    prev_time_value = get_posix_clock_time ();
    
    /* Do some work here */
    
    /* Final time */
    time_value = get_posix_clock_time ();
    
    /* Time difference */
    time_diff = time_value - prev_time_value;
    

La meilleure stratégie de repli est d'utiliser l'appel DosTmrQueryTime: il est pas monotones, mais il offre une très bonne résolution. L'idée est la même que <=>, mais pour obtenir une valeur de temps vous devez:

#include <time.h>
#include <sys/time.h>
#include <stdint.h>

uint64_t get_gtod_clock_time ()
{
    struct timeval tv;

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

Encore une fois, la valeur de temps est réduite à microsecondes.

SGI IRIX

IRIX a l'appel, mais il manque <=> <=>. Au contraire, il a sa propre source d'horloge monotones définie comme que vous devriez <=> utiliser au lieu de avec <=> <=>.

Solaris et HP-UX

Solaris a sa propre interface de minuterie haute résolution qui renvoie la <=> valeur actuelle du temporisateur en nanosecondes. Bien que les nouvelles versions de Solaris peuvent avoir <=>, vous pouvez coller à si vous avez besoin <=> pour soutenir les anciennes versions Solaris.

L'utilisation est simple:

#include <sys/time.h>

void time_measure_example ()
{
    hrtime_t prev_time_value, time_value;
    hrtime_t time_diff;

    /* Initial time */
    prev_time_value = gethrtime ();

    /* Do some work here */

    /* Final time */
    time_value = gethrtime ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

HP-UX ne dispose pas <=>, mais il prend en charge que vous devez <=> utiliser de la même manière que sur Solaris.

BeOS

BeOS a aussi sa propre interface de minuterie haute résolution qui renvoie le <=> nombre de microsecondes se sont écoulés depuis l'ordinateur a été démarré.

Exemple d'utilisation:

#include <kernel/OS.h>

void time_measure_example ()
{
    bigtime_t prev_time_value, time_value;
    bigtime_t time_diff;

    /* Initial time */
    prev_time_value = system_time ();

    /* Do some work here */

    /* Final time */
    time_value = system_time ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

OS / 2

OS / 2 a sa propre API pour récupérer l'horodatage de haute précision:

  • Query une fréquence d'horloge (tiques par unité) avec <=> (pour compilateur GCC):

    #define INCL_DOSPROFILE
    #define INCL_DOSERRORS
    #include <os2.h>
    #include <stdint.h>
    
    ULONG freq;
    
    DosTmrQueryFreq (&freq);
    
  • interroger la valeur courante avec les tiques <=>:

    QWORD    tcounter;
    unit64_t time_low;
    unit64_t time_high;
    unit64_t timestamp;
    
    if (DosTmrQueryTime (&tcounter) == NO_ERROR) {
        time_low  = (unit64_t) tcounter.ulLo;
        time_high = (unit64_t) tcounter.ulHi;
    
        timestamp = (time_high << 32) | time_low;
    }
    
  • Echelle les tiques au temps écoulé, à savoir de microsecondes:

    uint64_t usecs = (prev_timestamp - timestamp) / (freq / 1000000);
    

Exemple mise en œuvre

Vous pouvez jeter un oeil à la bibliothèque plibsys qui met en œuvre toutes les stratégies décrites ci-dessus (voir ptimeprofiler * .c pour plus de détails).

timespec_get de C11

Retourne à nanosecondes, arrondi à la résolution de la mise en œuvre.

On dirait un ripoff ANSI de POSIX »clock_gettime.

Exemple: un est fait tous les printf 100ms sur Ubuntu 15.10:

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

static long get_nanos(void) {
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    return (long)ts.tv_sec * 1000000000L + ts.tv_nsec;
}

int main(void) {
    long nanos;
    long last_nanos;
    long start;
    nanos = get_nanos();
    last_nanos = nanos;
    start = nanos;
    while (1) {
        nanos = get_nanos();
        if (nanos - last_nanos > 100000000L) {
            printf("current nanos: %ld\n", nanos - start);
            last_nanos = nanos;
        }
    }
    return EXIT_SUCCESS;
}

Le C11 N1570 projet de norme 7.27.2.5 "La fonction timespec_get dit":

  

Si la base est TIME_UTC, le membre tv_sec est réglé sur le nombre de secondes écoulées depuis une   la mise en oeuvre époque définie, tronquée à une valeur entière et l'élément est tv_nsec   définir au nombre entier de nanosecondes, arrondi à la résolution de l'horloge système. (321)

     

321) Bien qu'un objet struct timespec décrit fois avec la résolution nanoseconde, la mise à disposition   la résolution dépend du système et peut même être supérieur à 1 seconde.

11 C ++ aussi obtenu std::chrono::high_resolution_clock: C ++ multi-plateforme haute résolution minuterie

glibc 2.21 mise en œuvre

Présent dans sysdeps/posix/timespec_get.c comme:

int
timespec_get (struct timespec *ts, int base)
{
  switch (base)
    {
    case TIME_UTC:
      if (__clock_gettime (CLOCK_REALTIME, ts) < 0)
        return 0;
      break;

    default:
      return 0;
    }

  return base;
}

si clairement:

  • n'est actuellement pris en charge TIME_UTC

  • avant de __clock_gettime (CLOCK_REALTIME, ts), qui est une API Posix: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html

    Linux x86-64 a un appel système man clock_gettime.

    Notez que ce n'est pas une méthode micro-étalonnage fail-preuve parce que:

    • getrusage() dit que cette mesure peut avoir des discontinuités si vous changez un certain réglage de l'heure du système pendant que votre programme fonctionne. Cela devrait être un événement rare bien sûr, et vous pourriez être en mesure de l'ignorer.

    • mesure le temps de mur, donc si le planificateur décide d'oublier votre tâche, il semble courir plus longtemps.

    Pour ces raisons pourrait être un <=> meilleur meilleur outil d'analyse comparative POSIX, malgré sa précision maximale inférieure à la microseconde.

    Plus d'informations sur: Mesure temps sous Linux - temps vs vs horloge getrusage vs vs clock_gettime gettimeofday vs timespec_get

La meilleure précision que vous pouvez éventuellement obtenir est par l'utilisation du x86 seule instruction « rdtsc », qui peut fournir une résolution de niveau d'horloge (ne doit évidemment tenir compte du coût de l'rdtsc appeler lui-même, qui peut être mesurée facilement au démarrage de l'application).

La principale prise ici mesure le nombre d'horloges par seconde, ce qui ne devrait pas être trop dur.

La réponse acceptée est bonne enough.But ma solution est plus simple.I tester dans Linux, gcc utilisation (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.

Alse utilisation gettimeofday, le tv_sec est la partie du deuxième, et les tv_usec microsecondes pas millisecondes .

long currentTimeMillis() {
  struct timeval time;
  gettimeofday(&time, NULL);

  return time.tv_sec * 1000 + time.tv_usec / 1000;
}

int main() {
  printf("%ld\n", currentTimeMillis());
  // wait 1 second
  sleep(1);
  printf("%ld\n", currentTimeMillis());
  return 0;
 }

impression:

1522139691342 1522139692342, exactement une seconde.

Sous Windows:

SYSTEMTIME t;
GetLocalTime(&t);
swprintf_s(buff, L"[%02d:%02d:%02d:%d]\t", t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top