Ist gettimeofday () garantiert die Mikrosekunde Auflösung sein?

stimmen
82

Ich bin Portierung ein Spiel, das ursprünglich für die Win32-API geschrieben wurde, auf Linux (na ja, die OS X-Port des Win32-Port auf Linux portieren).

Ich habe realisiert , QueryPerformanceCounterindem die uSeconds da der Prozess starten:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

Dies, verbunden mit QueryPerformanceFrequency()einer konstanten 1000000 wie die Frequenz gibt, funktioniert gut auf meinem Rechner , mir eine 64 - Bit - Variable gibt , die enthält uSecondsseit der Inbetriebnahme des Programms.

So ist dieses tragbare? Ich will nicht zu entdecken , es funktioniert anders , wenn der Kernel in einer bestimmten Weise oder so etwas kompiliert wurde. Mir geht es gut mit ihm ist nicht tragbar auf etwas anderes als Linux, aber.

Veröffentlicht am 01/08/2008 um 15:36
quelle vom benutzer
In anderen Sprachen...                            


10 antworten

stimmen
54

Könnte sein. Aber Sie haben größere Probleme. gettimeofday()führen zu falschen Timings kann , wenn Prozesse auf Ihrem System, das den Timer zu ändern (dh ntpd). Auf einem „normalen“ Linux, glaube ich jedoch die Auflösung von gettimeofday()10us ist. Es kann folglich vorwärts und rückwärts und Zeit, springen, auf der Grundlage der Prozesse auf dem System ausgeführt wird . Damit wird an die Antwort auf Ihre Frage nicht.

Sie sollten prüfen clock_gettime(CLOCK_MONOTONIC)für Zeitintervalle. Es leidet unter mehreren weniger Probleme aufgrund Dinge wie Multi-Core - Systemen und externen Takteinstellungen.

Schauen Sie auch in der clock_getres()Funktion.

Beantwortet am 01/08/2008 um 15:53
quelle vom benutzer

stimmen
39

Hohe Auflösung, geringes Overhead-Timing für Intel-Prozessoren

Wenn Sie auf Intel-Hardware sind, ist hier, wie die CPU-Echtzeit-Befehlszähler zu lesen. Es wird Ihnen sagen, die Anzahl der CPU-Zyklen ausgeführt, da der Prozessor gestartet wurde. Dies ist wahrscheinlich der feinkörnigste Zähler Sie für die Leistungsmessung erhalten.

Beachten Sie, dass dies die Anzahl der CPU-Zyklen ist. Unter Linux können Sie die CPU-Geschwindigkeit von / proc / cpuinfo und dividieren erhalten Sie die Anzahl der Sekunden erhalten. Konvertieren dieser zu einem Doppel ist ganz praktisch.

Als ich das auf meiner Box laufen, bekomme ich

11867927879484732
11867927879692217
it took this long to call printf: 207485

Hier ist der Leitfaden für Intel - Entwickler , die Tonnen von Detail gibt.

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

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
Beantwortet am 02/08/2008 um 09:08
quelle vom benutzer

stimmen
18

@Bernard:

Ich muss zugeben, die meisten von Ihrem Beispiel ging direkt über meinen Kopf. Es tut kompilieren und scheint, wenn auch zu arbeiten. Ist das sicher für SMP-Systeme oder Speedstep?

Das ist eine gute Frage ... Ich denke, der Code ist in Ordnung. Aus praktischer Sicht, verwenden wir es jeden Tag in meiner Firma, und wir laufen auf eine ziemlich breite Palette von Boxen, alles von 2 bis 8 Cores. Natürlich YMMV, etc, aber es scheint ein zuverlässiger und mit geringen Overhead zu seinem Verfahren des Timings (weil es keinen Kontextwechsel in System-Raum machen).

Im Allgemeinen, wie es funktioniert, ist:

  • deklarieren den Block des Assemblercode zu sein (und flüchtig, so dass die Optimierer lassen sie allein).
  • führt den CPUID-Befehl. Neben einige CPU-Informationen bekommen (was wir tun, was nicht mit) es der betroffene synchronisiert Ausführungspuffer der CPU, so dass die Zeiten nicht von Out-of-Order-Ausführung.
  • führen Sie den RDTSC (Lesezeitstempel) Ausführung. Dies holt die Anzahl von Maschinenzyklen ausgeführt, da der Prozessor zurückgesetzt wurde. Dies ist ein 64-Bit-Wert, so mit aktuellen CPU-Geschwindigkeiten wird es alle 194 Jahre oder so umschlingen. Interessanterweise wurde in der ursprünglichen Pentium Referenz, beachten sie es umschlingt alle 5800 Jahre oder so.
  • die letzten paar Zeilen speichern die Werte aus den Registern in die Variablen hallo und lo, und setzt das in den 64-Bit-Rückgabewert.

Besondere Hinweise:

  • Out-of-Order-Ausführung kann zu falschen Ergebnissen führen, so führen wir die „CPUID“ Instruktion, die zusätzlich zu geben Ihnen einige Informationen über die CPU auch alle Out-of-Order-Befehlsausführung synchronisiert.

  • Die meisten Betriebssysteme synchronisieren die Zähler auf der CPUs, wenn sie beginnen, so die Antwort ist gut innerhalb von ein paar Nanosekunden.

  • Der hibernating Kommentar ist wohl wahr, aber in der Praxis werden Sie wahrscheinlich kümmern sich nicht um Timings über den Ruhezustand Grenzen.

  • in Bezug auf Speedstep: Neuere Intel-CPUs für die Geschwindigkeitsänderungen kompensiert und gibt eine angepasste Zählung. Ich habe eine schnelle Scan über einige der Kisten auf unserem Netz und fand nur eine Box, die es nicht haben: ein Pentium 3 einige alte Datenbankserver ausgeführt wird. (Diese sind Linux-Boxen, so dass ich überprüft mit: grep CONSTANT_TSC / proc / cpuinfo)

  • Ich bin mir nicht sicher über die AMD-CPUs, wir sind in erster Linie ein Intel-Shop, obwohl ich einige unserer Low-Level-Systeme Gurus wissen, hat einen AMD-Auswertung.

Hoffen, dass diese erfüllen Ihre Neugier, es ist ein interessantes und (IMHO) untersuchtes Gebiet der Programmierung. Sie wissen, wann Jeff und Joel gesprochen haben, ob ein Programmierer sollte C wissen? Ich war bei ihnen rief: „vergessen Hey, das High-Level-C stuff ... Assembler ist, was Sie sollten lernen, wenn Sie wollen wissen, was der Computer tut!“

Beantwortet am 04/08/2008 um 01:51
quelle vom benutzer

stimmen
14

Vielleicht interessiert sein Linux - FAQ fürclock_gettime(CLOCK_REALTIME)

Beantwortet am 18/08/2008 um 16:51
quelle vom benutzer

stimmen
11

Wein ist eigentlich gettimeofday () Queryperformancecounter zu implementieren () und es bekannt ist, viele Windows-Spiele funktionieren auf Linux und Mac zu machen.

startet http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

führt zu http://source.winehq.org/source/dlls/ntdll/time.c#L448

Beantwortet am 04/08/2008 um 15:44
quelle vom benutzer

stimmen
9

So sagt es ausdrücklich Mikrosekunden, sagt aber die Auflösung der Systemuhr nicht spezifiziert ist. Ich nehme an Auflösung bedeutet in diesem Zusammenhang, wie der kleinste Betrag, den sie jemals erhöht werden?

Die Datenstruktur wird als mit Mikrosekunden als eine Einheit der Messung definiert, aber das bedeutet nicht, dass die Uhr oder das Betriebssystem ist tatsächlich in der Lage, die fein zu messen.

Wie andere Leute vorgeschlagen haben, gettimeofday()ist schlecht , weil die Zeiteinstellung kann Taktverschiebung verursachen und Ihre Berechnung abwerfen. clock_gettime(CLOCK_MONOTONIC)ist das, was Sie wollen, und clock_getres()Sie die Genauigkeit Ihrer Uhr wird es zeigen.

Beantwortet am 02/08/2008 um 18:57
quelle vom benutzer

stimmen
8

Die tatsächliche Auflösung von gettimeofday () ist abhängig von der Hardware-Architektur. Intel-Prozessoren sowie SPARC-Rechner bieten hochauflösende Timer, die Mikrosekunden messen. Andere Hardware-Architekturen zurückgreifen, um den Timer des Systems, die bis zu 100 Hz typischerweise eingestellt ist. In solchen Fällen wird die Zeitauflösung ungenauer.

Ich erhielt diese Antwort aus Hohen Auflösung Zeitmessung und Zeitgebern, Teil I

Beantwortet am 01/08/2008 um 15:55
quelle vom benutzer

stimmen
5

Diese Antwort erwähnt Probleme mit der Uhr eingestellt werden. Sowohl Ihre Probleme tick Einheiten zu gewährleisten und die Probleme mit der Zeit eingestellt werden , werden gelöst in C ++ 11 mit der <chrono>Bibliothek.

Die Uhr std::chrono::steady_clockist garantiert nicht eingestellt werden, und darüber hinaus wird es mit einer konstanten Geschwindigkeit relativ zur Echtzeit vorantreiben , so Technologien wie Speedstep muss es nicht beeinflussen.

Sie können typsichere Einheiten erhalten , indem einer der Umwandlung von std::chrono::durationSpezialisierungen, wie std::chrono::microseconds. Bei dieser Art gibt es keine Zweideutigkeit über die von dem Tick - Wert verwendet Einheiten. Beachten Sie jedoch, dass die Uhr nicht notwendigerweise diese Auflösung. Sie können eine Dauer zu Attosekunden konvertieren , ohne tatsächlich , dass genau eine Uhr mit.

Beantwortet am 26/06/2012 um 16:57
quelle vom benutzer

stimmen
4

Aus meiner Erfahrung und von dem, was ich über das Internet gelesen habe, ist die Antwort „Nein“, ist nicht gewährleistet. Es hängt von der CPU-Geschwindigkeit, Betriebssystem, Geschmack von Linux, etc.

Beantwortet am 01/08/2008 um 15:46
quelle vom benutzer

stimmen
3

die RDTSC zu lesen, ist in SMP-Systemen nicht zuverlässig, da jede CPU ihren eigenen Zähler und jeder Zähler hält nicht auf garantiert gegenüber einer anderen CPU synchronisiert.

Ich könnte versuchen , vorschlagen clock_gettime(CLOCK_REALTIME). Das Posix - Handbuch gibt an, dass dies auf allen kompatibelen Systemen umgesetzt werden sollte. Es kann eine Nanosekunde Zahl liefern, aber Sie werden wahrscheinlich wollen prüfen , die clock_getres(CLOCK_REALTIME)auf dem System , um zu sehen , was die tatsächliche Auflösung ist.

Beantwortet am 18/08/2008 um 16:40
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more