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
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 …?
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
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
jstedfast
Hier ist eine Header-Datei, die ich geschrieben habe, um ein einfaches Leistungsprofil zu erstellen (mit manuellen Timern):
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.
#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);
}
}
}
Aaron
Versuchen Sie mit der time.h-Bibliothek Folgendes:
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
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 😮
Todo: Sehen Sie, wo /proc/cpuinfo es bekommt … aber ich vermute, dass es das Zeitlimit erreicht … also ist es am besten, es in einem direkteren Format zu lesen, von wo aus der Kernel es aufbewahrt …
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