Gibt es eine Möglichkeit, die Zeit nur mit ANSI C mit einer Genauigkeit von Millisekunden oder mehr zu messen? Ich habe time.h durchsucht, aber nur Funktionen mit zweiter Genauigkeit gefunden.
c
portability
time-precision
corto
quelle
quelle
Antworten:
Es gibt keine ANSI C-Funktion, die eine bessere Auflösung als 1 Sekunde
gettimeofday
bietet, aber die POSIX-Funktion bietet eine Mikrosekundenauflösung. Die Uhrfunktion misst nur die Zeit, die ein Prozess für die Ausführung aufgewendet hat, und ist auf vielen Systemen nicht genau.Sie können diese Funktion folgendermaßen verwenden:
Dies kehrt
Time elapsed: 1.000870
auf meinem Computer zurück.quelle
timeval::tv_usec
es immer unter einer Sekunde ist, es ist eine Schleife. Dh um Zeitunterschiede von mehr als 1 Sekunde zu nehmen, sollten Sie:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
timersub
Funktion enthalten. Wir können dietval_result
Werte (tv_sec und tv_usec) unverändert verwenden.quelle
CLOCKS_PER_SEC / 1000
möglicherweise ungenau ist, was sich auf das Endergebnis auswirken kann (obwohl es meiner ErfahrungCLOCKS_PER_SEC
nach immer ein Vielfaches von 1000 war). Das Tun(1000 * clock()) / CLOCKS_PER_SEC
ist weniger anfällig für Ungenauigkeiten bei der Teilung, andererseits ist es anfälliger für Überläufe. Nur einige Punkte zu beachten.Ich benutze immer die Funktion clock_gettime () und gebe die Zeit von der Uhr CLOCK_MONOTONIC zurück. Die zurückgegebene Zeit ist die Zeit in Sekunden und Nanosekunden seit einem nicht näher bezeichneten Zeitpunkt in der Vergangenheit, z. B. dem Systemstart der Epoche.
quelle
clock_gettime(CLOCK_MONOTONIC, ...)
und es sogar das Feature-Test-Makro gibt_POSIX_MONOTONIC_CLOCK
.Implementierung einer tragbaren Lösung
Da hier bereits erwähnt wurde, dass es keine richtige ANSI-Lösung mit ausreichender Genauigkeit für das Zeitmessproblem gibt, möchte ich darüber schreiben, wie man eine tragbare und wenn möglich hochauflösende Zeitmesslösung erhält.
Monotone Uhr gegen Zeitstempel
Generell gibt es zwei Möglichkeiten der Zeitmessung:
Der erste verwendet einen monotonen Taktzähler (manchmal wird er als Tick-Zähler bezeichnet), der Ticks mit einer vordefinierten Frequenz zählt. Wenn Sie also einen Tick-Wert haben und die Frequenz bekannt ist, können Sie Ticks einfach in verstrichene Zeit umwandeln. Es ist tatsächlich nicht garantiert, dass eine monotone Uhr die aktuelle Systemzeit in irgendeiner Weise widerspiegelt. Sie kann auch Ticks seit einem Systemstart zählen. Es garantiert jedoch, dass eine Uhr unabhängig vom Systemstatus immer stärker hochgefahren wird. Normalerweise ist die Frequenz an eine hochauflösende Hardwarequelle gebunden, weshalb sie eine hohe Genauigkeit bietet (abhängig von der Hardware, aber der Großteil der modernen Hardware hat keine Probleme mit hochauflösenden Taktquellen).
Der zweite Weg liefert einen (Datums-) Zeitwert basierend auf dem aktuellen Systemuhrwert. Es kann auch eine hohe Auflösung haben, hat jedoch einen großen Nachteil: Diese Art von Zeitwert kann durch verschiedene Systemzeitanpassungen beeinflusst werden, z. B. Zeitzonenänderung, Änderung der Sommerzeit (DST), Aktualisierung des NTP-Servers, System-Ruhezustand usw. auf. Unter bestimmten Umständen können Sie einen negativen Wert für die verstrichene Zeit erhalten, der zu einem undefinierten Verhalten führen kann. Tatsächlich ist diese Art von Zeitquelle weniger zuverlässig als die erste.
Die erste Regel bei der Zeitintervallmessung ist daher, wenn möglich eine monotone Uhr zu verwenden. Es hat normalerweise eine hohe Präzision und ist vom Design her zuverlässig.
Fallback-Strategie
Bei der Implementierung einer tragbaren Lösung sollte eine Fallback-Strategie in Betracht gezogen werden: Verwenden Sie eine monotone Uhr, falls verfügbar, und greifen Sie auf Zeitstempel zurück, wenn das System keine monotone Uhr enthält.
Windows
Es gibt einen großartigen Artikel mit dem Titel " Erfassen hochauflösender Zeitstempel auf MSDN zur Zeitmessung unter Windows", in dem alle Details beschrieben werden, die Sie möglicherweise zur Software- und Hardwareunterstützung benötigen. Um einen hochpräzisen Zeitstempel unter Windows zu erhalten, sollten Sie:
Abfragen einer Timer-Frequenz (Ticks pro Sekunde) mit QueryPerformanceFrequency :
Die Timer-Frequenz ist beim Systemstart festgelegt, sodass Sie sie nur einmal abrufen müssen.
Fragen Sie den aktuellen Ticks-Wert mit QueryPerformanceCounter ab :
Skalieren Sie die Ticks auf die verstrichene Zeit, dh auf Mikrosekunden:
Laut Microsoft sollten Sie unter Windows XP und späteren Versionen in den meisten Fällen keine Probleme mit diesem Ansatz haben. Sie können aber auch zwei Fallback-Lösungen unter Windows verwenden:
GetTickCount
, ist jedoch ab Windows Vista und höher verfügbar.OS X (macOS)
OS X (macOS) verfügt über eigene Mach-Absolutzeiteinheiten, die eine monotone Uhr darstellen. Der beste Einstieg ist der Apple-Artikel Technische Fragen und Antworten QA1398: Mach Absolute Time Units, in dem (anhand der Codebeispiele) beschrieben wird, wie mithilfe der Mach-spezifischen API monotone Ticks abgerufen werden. Es gibt auch eine lokale Frage mit dem Namen clock_gettime-Alternative in Mac OS X, die Sie am Ende möglicherweise etwas verwirrt darüber macht, was Sie mit dem möglichen Wertüberlauf tun sollen, da die Zählerfrequenz in Form von Zähler und Nenner verwendet wird. Ein kurzes Beispiel, wie man die verstrichene Zeit erhält:
Holen Sie sich den Taktfrequenzzähler und Nenner:
Sie müssen das nur einmal tun.
Fragen Sie den aktuellen Tick-Wert ab mit
mach_absolute_time
:Skalieren Sie die Ticks mit dem zuvor abgefragten Zähler und Nenner auf die verstrichene Zeit, dh auf Mikrosekunden:
Die Hauptidee, um einen Überlauf zu verhindern, besteht darin, die Ticks auf die gewünschte Genauigkeit zu verkleinern, bevor Zähler und Nenner verwendet werden. Da die anfängliche Timer-Auflösung in Nanosekunden angegeben ist, teilen wir sie durch
1000
Mikrosekunden. Sie finden den gleichen Ansatz wie in time_mac.c von Chromium . Wenn Sie wirklich eine Genauigkeit von Nanosekunden benötigen, lesen Sie bitte Wie kann ich mach_absolute_time verwenden, ohne überzulaufen? .Linux und UNIX
Der
clock_gettime
Anruf ist der beste Weg auf jedem POSIX-freundlichen System. Es kann die Zeit von verschiedenen Uhrquellen abfragen, und die, die wir brauchen, istCLOCK_MONOTONIC
. Nicht alle Systeme, dieclock_gettime
UnterstützungCLOCK_MONOTONIC
bieten. Daher müssen Sie zunächst die Verfügbarkeit überprüfen:_POSIX_MONOTONIC_CLOCK
ein Wert definiert ist,>= 0
bedeutet dies, dass dieserCLOCK_MONOTONIC
verfügbar ist.Wenn dies
_POSIX_MONOTONIC_CLOCK
definiert ist,0
bedeutet dies, dass Sie zusätzlich prüfen sollten, ob es zur Laufzeit funktioniert. Ich empfehle Folgendessysconf
:Die Verwendung von
clock_gettime
ist ziemlich einfach:Holen Sie sich den Zeitwert:
Ich habe die Zeit hier auf Mikrosekunden reduziert.
Berechnen Sie die Differenz zum vorherigen Zeitwert auf dieselbe Weise:
Die beste Fallback-Strategie besteht darin, den
gettimeofday
Anruf zu verwenden: Er ist nicht monoton, bietet jedoch eine recht gute Auflösung. Die Idee ist die gleiche wie beiclock_gettime
, aber um einen Zeitwert zu erhalten, sollten Sie:Auch hier wird der Zeitwert auf Mikrosekunden verkleinert.
SGI IRIX
IRIX hat den
clock_gettime
Anruf, aber es fehltCLOCK_MONOTONIC
. Stattdessen hat er seine eigene monotone Taktquelle definiert alsCLOCK_SGI_CYCLE
die sollten Sie statt verwendenCLOCK_MONOTONIC
mitclock_gettime
.Solaris und HP-UX
Solaris verfügt über eine eigene hochauflösende Timer-Schnittstelle,
gethrtime
die den aktuellen Timer-Wert in Nanosekunden zurückgibt. Obwohl die neueren Versionen von Solaris möglicherweise vorhanden sindclock_gettime
, können Sie sich daran halten,gethrtime
wenn Sie alte Solaris-Versionen unterstützen müssen.Die Verwendung ist einfach:
HP-UX fehlt
clock_gettime
, aber es unterstützt,gethrtime
was Sie auf die gleiche Weise wie unter Solaris verwenden sollten.BeOS
BeOS verfügt außerdem über eine eigene hochauflösende Timer-Schnittstelle,
system_time
die die Anzahl der Mikrosekunden zurückgibt, die seit dem Start des Computers vergangen sind.Anwendungsbeispiel:
OS / 2
OS / 2 verfügt über eine eigene API zum Abrufen hochpräziser Zeitstempel:
Abfrage einer Timerfrequenz (Ticks pro Einheit) mit
DosTmrQueryFreq
(für GCC-Compiler):Fragen Sie den aktuellen Ticks-Wert ab mit
DosTmrQueryTime
:Skalieren Sie die Ticks auf die verstrichene Zeit, dh auf Mikrosekunden:
Beispielimplementierung
Sie können sich die plibsys- Bibliothek ansehen, die alle oben beschriebenen Strategien implementiert (Details siehe ptimeprofiler * .c).
quelle
timespec_get
: stackoverflow.com/a/36095407/895245timespec_get
ist nicht monoton.timespec_get
von C11Gibt bis zu Nanosekunden zurück, gerundet auf die Auflösung der Implementierung.
Sieht aus wie eine ANSI-Abzocke von POSIX '
clock_gettime
.Beispiel: a
printf
wird unter Ubuntu 15.10 alle 100 ms ausgeführt:Der C11 N1570 Standardentwurf 7.27.2.5 "Die Funktion timespec_get sagt":
C ++ 11 hat auch
std::chrono::high_resolution_clock
: C ++ Plattformübergreifender hochauflösender TimerImplementierung von glibc 2.21
Kann unter gefunden werden
sysdeps/posix/timespec_get.c
als:so klar:
Nur
TIME_UTC
wird derzeit unterstütztEs
__clock_gettime (CLOCK_REALTIME, ts)
wird an eine POSIX-API weitergeleitet: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlLinux x86-64 hat einen
clock_gettime
Systemaufruf.Beachten Sie, dass dies keine ausfallsichere Mikro-Benchmarking-Methode ist, weil:
man clock_gettime
sagt, dass diese Maßnahme Diskontinuitäten aufweisen kann, wenn Sie eine Systemzeiteinstellung ändern, während Ihr Programm ausgeführt wird. Dies sollte natürlich ein seltenes Ereignis sein, und Sie können es möglicherweise ignorieren.Dies misst die Wandzeit. Wenn der Planer also beschließt, Ihre Aufgabe zu vergessen, wird sie anscheinend länger ausgeführt.
Aus diesen Gründen
getrusage()
könnte es ein besseres, besseres POSIX-Benchmarking-Tool sein, trotz der geringeren maximalen Genauigkeit von Mikrosekunden.Weitere Informationen unter: Zeit unter Linux messen - Zeit gegen Uhr gegen getrusage gegen clock_gettime gegen gettimeofday gegen timespec_get?
quelle
Die beste Präzision, die Sie möglicherweise erzielen können, ist die Verwendung des x86-Befehls "rdtsc", der eine Auflösung auf Taktebene bietet (ne muss natürlich die Kosten des rdtsc-Aufrufs selbst berücksichtigen, an denen leicht gemessen werden kann Anwendungsstart).
Der Hauptfang hierbei ist die Messung der Anzahl der Uhren pro Sekunde, die nicht zu schwer sein sollte.
quelle
Die akzeptierte Antwort ist gut genug. Aber meine Lösung ist einfacher. Ich teste nur unter Linux und verwende gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.
Alse verwenden
gettimeofday
, dastv_sec
ist der Teil der zweiten, und dastv_usec
ist Mikrosekunden , nicht Millisekunden .Es druckt:
1522139691342 1522139692342
genau eine Sekunde.quelle
Unter Fenstern:
quelle