Wie messe ich ein Zeitintervall in C?

Lesezeit: 13 Minuten

Ich möchte die Zeit in C messen, und es fällt mir schwer, es herauszufinden. Alles, was ich will, ist so etwas:

  • einen Timer starten
  • eine Methode ausführen
  • Stoppen Sie den Timer
  • Melden Sie die benötigte Zeit (mindestens mikrogenau)

Jede Hilfe wäre willkommen.

(Ich kompiliere in Windows mit Mingw)

  • Datum-Uhrzeit oder CPU-Zeit? für letzteres siehe zB stackoverflow.com/questions/1380136/fast-elapsed-time-on-linux/…

    – Christoph

    27. Januar 2010 um 21:18 Uhr

Benutzeravatar von Daniel Vassallo
Daniel Wassallo

Hochauflösende Timer, die eine Auflösung von 1 Mikrosekunde bieten, sind systemspezifisch, sodass Sie auf verschiedenen Betriebssystemplattformen unterschiedliche Methoden anwenden müssen, um dies zu erreichen. Vielleicht interessieren Sie sich für den folgenden Artikel, der eine plattformübergreifende C++-Timer-Klasse basierend auf den unten beschriebenen Funktionen implementiert:

  • [Song Ho Ahn – High Resolution Timer][1]

Windows

Die Windows-API bietet Zeitfunktionen mit extrem hoher Auflösung: QueryPerformanceCounter()die die aktuell verstrichenen Ticks zurückgibt, und QueryPerformanceFrequency()die die Anzahl der Ticks pro Sekunde zurückgibt.

Beispiel:

#include <stdio.h>
#include <windows.h>                // for Windows APIs

int main(void)
{
    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;
    printf("%f ms.\n", elapsedTime);
}

Linux, Unix und Mac

Für Unix- oder Linux-basierte Systeme können Sie verwenden gettimeofday(). Diese Funktion ist in “sys/time.h” deklariert.

Beispiel:

#include <stdio.h>
#include <sys/time.h>                // for gettimeofday()

int main(void)
{
    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
    printf("%f ms.\n", elapsedTime);
}

  • Ich denke, es sollte struct timeval sein, nicht nur timeval.

    – sofort717

    24. Oktober 2013 um 16:29 Uhr

  • struct timeval hat bei mir funktioniert (einige GCC ARM-Compiler)

    – Micha

    5. Dezember 2014 um 9:36 Uhr

  • Auf Android meldet sich ein ungewöhnlich großer Wert. Wenn t2.tv_usec=925311 und t1.tv_usec=861102, wird elapsedTime als 262144000 gemeldet. Dies ist nach dem Hinzufügen von „struct“, wie schon erwähnt717.

    – Nikolaus

    31. März 2015 um 0:03 Uhr

  • Diese Lösung ist für C ++, aber die Fragen stellen sich für C. Warum wird diese akzeptiert …?

    – Ethan Yang

    23. April 2017 um 5:15 Uhr


  • Ich brauche eine Version für C. Ist das möglich?

    – kam

    15. September 2019 um 8:58 Uhr

Benutzeravatar von Paul R
Paul R

Unter Linux können Sie verwenden clock_gettime():

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

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

clock_gettime(CLOCK_REALTIME, &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

  • Warum die Ablehnung? Sehen: linux.die.net/man/3/clock_gettime für weitere Informationen zu clock_gettime.

    – PaulR

    17. Juli 2012 um 5:30 Uhr


  • Würde nicht CLOCK_REALTIME angemessener sein? Siehe: stackoverflow.com/questions/23483261/…

    – Mahyar Mirrashed

    29. Juni um 7:20 Uhr

  • @MahyarMirrashed: ja, zum Zeitpunkt des Schreibens (2010) CLOCK_REALTIME war nicht allgemein verfügbar, aber es ist jetzt wahrscheinlich sicher zu verwenden.

    – PaulR

    29. Juni um 9:25 Uhr


Benutzeravatar von jstedfast
jstedfast

Hier ist eine Header-Datei, die ich geschrieben habe, um ein einfaches Leistungsprofil zu erstellen (mit manuellen Timern):

#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__ */

Das ztime() Die Funktion ist die Hauptlogik, die Sie benötigen – sie erhält die aktuelle Uhrzeit und speichert sie in einem 64-Bit-Uint, gemessen in Mikrosekunden. Sie können dann später einfache Berechnungen anstellen, um die verstrichene Zeit herauszufinden.

Das ZenTimer*() Funktionen sind nur Hilfsfunktionen, um einen Zeiger auf eine einfache Timer-Struktur zu nehmen, ztimer_t, die die Startzeit und die Endzeit aufzeichnet. Das ZenTimerPause()/ZenTimerResume() Mit den Funktionen können Sie den Timer anhalten und fortsetzen, falls Sie zum Beispiel einige Debugging-Informationen ausdrucken möchten, die Sie nicht zeitlich festlegen möchten.

Eine Kopie der ursprünglichen Header-Datei finden Sie unter http://www.gnome.org/~fejj/code/zentimer.h für den unwahrscheinlichen Fall, dass ich das HTML-Escape von < oder so etwas durcheinander gebracht habe. Es ist unter MIT/X11 lizenziert, Sie können es also gerne in jedes Ihrer Projekte kopieren.

Das Folgende ist eine Gruppe vielseitiger C-Funktionen für das Timer-Management, die auf dem Systemaufruf gettimeofday() basieren. Alle Timer-Eigenschaften sind in einer einzigen Ticktimer-Struktur enthalten – das gewünschte Intervall, die Gesamtlaufzeit seit der Timer-Initialisierung, ein Zeiger auf den gewünschten Callback, den Sie aufrufen möchten, die Anzahl der Callback-Aufrufe. Eine Callback-Funktion würde so aussehen:

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

Um einen Timer zu initialisieren und zu starten, rufen Sie ticktimer_init(your_timer, interval, TICKTIMER_RUN, your_timer_cb, 0) auf.

Rufen Sie in der Hauptschleife Ihres Programms ticktimer_tick(your_timer) auf und es wird entschieden, ob die angemessene Zeit vergangen ist, um den Callback aufzurufen.

Um einen Timer zu stoppen, rufen Sie einfach ticktimer_ctl(your_timer, TICKTIMER_STOP) auf.

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);
    }
  }
}

Benutzeravatar von Aaron
Aaron

Versuchen Sie mit der time.h-Bibliothek Folgendes:

long start_time, end_time, elapsed;

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

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

  • CLK_TCK ist obsolet; verwenden CLOCKS_PER_SEC stattdessen

    – Christoph

    27. Januar 2010 um 21:35 Uhr

  • clock() erreicht keine Auflösung von 1 Mikrosekunde. Eine Quelle gibt an, dass die Auflösung etwa 15 ms beträgt: songho.ca/misc/timer/timer.html

    – Daniel Vasallo

    27. Januar 2010 um 21:38 Uhr


  • Die Granularität von clock() variiert auf verschiedenen Systemen.

    – Lyxera

    23. Mai 2012 um 8:44 Uhr


  • clock() gibt die vom Programm verbrauchte Prozessorzeit zurück. Verwenden sleep, usleepusw. können Probleme in Ihrer Software verursachen.

    – Bayu

    4. Juni 2019 um 16:36 Uhr

Neils Benutzeravatar
Neil

Wenn Ihr Linux-System dies unterstützt, sollte clock_gettime(CLOCK_MONOTONIC) ein hochauflösender Timer sein, der von Änderungen des Systemdatums (z. B. NTP-Daemons) nicht betroffen ist.

  • CLK_TCK ist obsolet; verwenden CLOCKS_PER_SEC stattdessen

    – Christoph

    27. Januar 2010 um 21:35 Uhr

  • clock() erreicht keine Auflösung von 1 Mikrosekunde. Eine Quelle gibt an, dass die Auflösung etwa 15 ms beträgt: songho.ca/misc/timer/timer.html

    – Daniel Vasallo

    27. Januar 2010 um 21:38 Uhr


  • Die Granularität von clock() variiert auf verschiedenen Systemen.

    – Lyxera

    23. Mai 2012 um 8:44 Uhr


  • clock() gibt die vom Programm verbrauchte Prozessorzeit zurück. Verwenden sleep, usleepusw. können Probleme in Ihrer Software verursachen.

    – Bayu

    4. Juni 2019 um 16:36 Uhr

Tolle Antworten für GNU-Umgebungen oben und unten …

Aber … was ist, wenn Sie kein Betriebssystem verwenden? (oder ein PC für diese Angelegenheit, oder Sie müssen Ihre Timer-Interrupts selbst timen?) Hier ist eine Lösung, die den x86-CPU-Timestamp-Zähler direkt verwendet … Nicht, weil dies eine gute Praxis ist oder jemals durchgeführt werden sollte, wenn Sie unter laufen ein Betriebssystem…

  • Vorbehalt: Funktioniert nur auf x86 mit deaktivierter Frequenzskalierung.
  • Funktioniert unter Linux nur auf Kerneln ohne Tick

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,mt;

     // mt is the divisor to give microseconds

     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 - if you use the equivalent assembler for
     // that CPU
     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);

     s[9]=(char)0;
     strcpy(&s[4],&s[5]);
     mt=atoi(s);

     printf("#define mt %u // (%s Hz) hardcode this for your a CPU-specific binary ;-)\n",mt,s);

     tick1 = getticks();
     time = (unsigned)((tick1-tick)/mt);
     printf("%u ms\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;
}

kompilieren und ausführen mit

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

Es liest den Divisor für Ihre CPU aus /proc/cpuinfo und zeigt an, wie lange es in Mikrosekunden gedauert hat, diesen zu lesen, sowie wie lange es in Mikrosekunden dauert, sleep(1) auszuführen … Angenommen, die Mhz-Bewertung in /proc/ cpuinfo enthält immer 3 Nachkommastellen 😮

1410200cookie-checkWie messe ich ein Zeitintervall in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy