106 Stimmen

Ist garantiert, dass gettimeofday() eine Auflösung von Mikrosekunden hat?

Ich portiere ein Spiel, das ursprünglich für die Win32-API geschrieben wurde, auf Linux (oder besser gesagt, ich portiere die OS X-Portierung der Win32-Portierung auf Linux).

Ich habe implementiert QueryPerformanceCounter durch Angabe der uSekunden seit dem Start des Prozesses:

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, gepaart mit QueryPerformanceFrequency() mit einer konstanten Frequenz von 1000000, funktioniert gut auf meinem Rechner so dass ich eine 64-Bit-Variable erhalte, die Folgendes enthält uSeconds seit dem Start des Programms.

Also Ist das tragbar? Ich möchte nicht herausfinden, dass es anders funktioniert, wenn der Kernel auf eine bestimmte Weise kompiliert wurde oder so etwas. Ich habe jedoch kein Problem damit, dass es nicht auf andere Systeme als Linux portierbar ist.

63voto

Louis Brandy Punkte 17498

Vielleicht. Aber Sie haben größere Probleme. gettimeofday() kann zu falschen Zeitangaben führen, wenn es auf Ihrem System Prozesse gibt, die den Timer verändern (z.B. ntpd). Auf einem "normalen" Linux, glaube ich jedoch, dass die Auflösung von gettimeofday() beträgt 10us. Er kann vorwärts und rückwärts springen und die Zeit folglich von den auf Ihrem System laufenden Prozessen abhängig machen. Damit ist die Antwort auf Ihre Frage eigentlich nein.

Sie sollten sich informieren über clock_gettime(CLOCK_MONOTONIC) für Zeitintervalle. Er leidet unter einigen weniger Problemen aufgrund von Dingen wie Multi-Core-Systemen und externen Takteinstellungen.

Prüfen Sie auch die clock_getres() Funktion.

1 Stimmen

Clock_gettime ist nur auf dem neuesten Linux vorhanden. Andere Systeme haben nur gettimeofday()

3 Stimmen

@vitaly.v.ch es ist POSIX, also ist es nicht nur Linux und "newist"? sogar "Enterprise"-Distributionen wie Red Hat Enterprise Linux basieren auf 2.6.18, das clock_gettime hat, also nein, nicht sehr neu (das Datum der Manpage in RHEL ist 2004-März-12, also ist es schon eine Weile da), es sei denn, Sie sprechen von WIRKLICH VERRÜCKTEN ALTEN Kerneln, WAS meinen Sie?

0 Stimmen

Clock_gettime wurde 2001 in POSIX aufgenommen. Soweit ich weiß, ist clock_gettime() derzeit in Linux 2.6 und qnx implementiert, aber Linux 2.4 wird derzeit in vielen Produktionssystemen verwendet.

45voto

Mark Harrison Punkte 281807

Hochauflösendes Timing mit geringem Overhead für Intel-Prozessoren

Wenn Sie mit Intel-Hardware arbeiten, können Sie den Echtzeit-Befehlszähler der CPU folgendermaßen auslesen. Er zeigt Ihnen die Anzahl der CPU-Zyklen an, die seit dem Hochfahren des Prozessors ausgeführt wurden. Dies ist wahrscheinlich der feinkörnigste Zähler, den Sie für Leistungsmessungen bekommen können.

Beachten Sie, dass dies die Anzahl der CPU-Zyklen ist. Unter Linux können Sie die CPU-Geschwindigkeit aus /proc/cpuinfo ablesen und dividieren, um die Anzahl der Sekunden zu erhalten. Die Umwandlung in ein Double ist recht praktisch.

Wenn ich dies auf meinem Rechner ausführe, erhalte ich

11867927879484732
11867927879692217
it took this long to call printf: 207485

Hier ist die Handbuch für Intel-Entwickler die viele Details enthält.

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

11 Stimmen

Beachten Sie, dass der TSC möglicherweise nicht immer zwischen den Kernen synchronisiert ist, möglicherweise anhält oder seine Frequenz ändert, wenn der Prozessor in einen Modus mit geringerer Leistungsaufnahme wechselt (und Sie keine Möglichkeit haben, dies zu erkennen), und im Allgemeinen nicht immer zuverlässig ist. Der Kernel ist in der Lage zu erkennen, wann er zuverlässig ist, andere Alternativen wie HPET und ACPI PM Timer zu erkennen und automatisch die beste auszuwählen. Es ist eine gute Idee, immer den Kernel für die Zeitmessung zu verwenden, es sei denn, Sie sind wirklich sicher, dass der TSC stabil und monoton ist.

12 Stimmen

Der TSC auf Core- und höheren Intel-Plattformen wird über mehrere CPUs hinweg synchronisiert. y wird mit einer konstanten Frequenz erhöht, unabhängig vom Zustand der Energieverwaltung. Siehe Intel Software Developer's Manual, Vol. 3 Abschnitt 18.10. Die Rate, mit der der Zähler inkrementiert, ist jedoch no die gleiche Frequenz wie die der CPU. Der TSC erhöht sich bei "der maximalen aufgelösten Frequenz der Plattform, die gleich dem Produkt aus skalierbarer Busfrequenz und maximalem aufgelöstem Busverhältnis ist" (Intel Software Developer's Manual, Vol. 3, Abschnitt 18.18.5). Sie erhalten diese Werte aus den modellspezifischen Registern (MSRs) der CPU.

7 Stimmen

Sie können die skalierbare Busfrequenz und das maximal aufgelöste Busverhältnis erhalten, indem Sie die modellspezifischen Register (MSRs) der CPU wie folgt abfragen: Skalierbare Busfrequenz == MSR_FSB_FREQ[2:0] id 0xCD, Maximales aufgelöstes Busverhältnis == MSR_PLATFORM_ID[12:8] id 0x17. Lesen Sie Intel SDM Vol.3 Appendix B.1, um die Registerwerte zu interpretieren. Sie können die msr-Tools unter Linux verwenden, um die Register abzufragen. kernel.org/pub/linux/utils/cpu/msr-tools

14voto

David Schlosnagle Punkte 4243

Das könnte Sie interessieren Linux-FAQ für clock_gettime(CLOCK_REALTIME)

11voto

Vincent Robert Punkte 34478

Wine verwendet gettimeofday(), um QueryPerformanceCounter() zu implementieren und ist dafür bekannt, dass es viele Windows-Spiele unter Linux und Mac zum Laufen bringt.

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

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

9voto

Die tatsächliche Auflösung von gettimeofday() hängt von der Hardware-Architektur ab. Intel-Prozessoren sowie SPARC-Maschinen bieten hochauflösende Timer, die Mikrosekunden messen. Andere Hardware-Architekturen greifen auf den Timer des Systems zurück, der normalerweise auf 100 Hz eingestellt ist. In solchen Fällen ist die Zeitauflösung weniger genau.

Diese Antwort erhielt ich von Hochauflösende Zeitmessung und Zeitgeber, Teil I

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X