Czy gettimeofday() ma gwarantowaną rozdzielczość mikrosekund?

Przenoszę grę, która została pierwotnie napisana dla Win32 API, na Linuksa (no cóż, przenoszenie portu OS X Z Portu Win32 na Linuksa).

Zaimplementowałem QueryPerformanceCounter podając uSeconds od uruchomienia procesu:

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

To, w połączeniu z QueryPerformanceFrequency() dając stałą 1000000 jako częstotliwość, działa dobrze na mojej Maszynie , dając mi zmienną 64 bitową, która zawiera uSeconds od momentu uruchomienia programu.

Więc czy to przenośne? nie chcę odkryj, że działa inaczej, jeśli jądro zostało skompilowane w określony sposób lub coś w tym stylu. Nie przeszkadza mi to, że nie jest przenośny na coś innego niż Linux.

Author: Rann Lifshitz, 2008-08-01

10 answers

Może. Ale masz większe problemy. gettimeofday() może spowodować nieprawidłowe timingi, jeśli w systemie są procesy, które zmieniają timer (ie, ntpd). Na" normalnym " Linuksie wydaje mi się jednak, że rozdzielczość gettimeofday() wynosi 10us. Może skakać do przodu i do tyłu, a co za tym idzie, w oparciu o procesy działające w Twoim systemie. To skutecznie sprawia, że odpowiedź na twoje pytanie nie.

Powinieneś sprawdzić clock_gettime(CLOCK_MONOTONIC) interwały czasowe. Cierpi na kilka mniej problemów z powodu rzeczy jak systemy wielordzeniowe i zewnętrzne ustawienia zegara.

Przyjrzyj się również funkcji clock_getres().

 56
Author: Louis Brandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-14 12:28:51

Wysoka rozdzielczość, niski czas narzutu dla procesorów Intel

Jeśli korzystasz ze sprzętu Intela, oto jak odczytać licznik instrukcji procesora w czasie rzeczywistym. Pokaże ci liczbę cykli procesora wykonanych od czasu uruchomienia procesora. Jest to prawdopodobnie najlepiej ziarnisty licznik, jaki można uzyskać do pomiaru wydajności.

Zauważ, że jest to liczba cykli procesora. W Linuksie możesz pobrać prędkość PROCESORA z /proc / cpuinfo i podzielić, aby uzyskać liczbę sekund. Konwersja tego do podwójnego jest bardzo przydatna.

Kiedy uruchamiam to na moim pudełku, dostaję

11867927879484732
11867927879692217
it took this long to call printf: 207485
Oto Intel developer ' s guide , który zawiera mnóstwo szczegółów.
#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);
}
 40
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-23 16:53:06

@Bernard:

Muszę przyznać, że większość twojego przykładu przerosła moją głowę. Kompiluje się i wydaje się działać. Czy jest to bezpieczne dla Systemów SMP czy SpeedStep?

To dobre pytanie... Myślę, że kod jest w porządku. Z praktycznego punktu widzenia używamy go w mojej firmie na co dzień, i pracujemy na dość szerokiej gamie pudełek, wszystko od 2-8 rdzeni. Oczywiście, YMMV, itp., ale wydaje się, że jest to niezawodne i niskie koszty (bo nie tworzy kontekstu switch into system-space) metoda czasu.

Ogólnie jak to działa to:

  • zadeklarować blok kodu jako asembler (i Lotny, więc optimizer pozostawi go w spokoju).
  • wykonaj instrukcję CPUID. Oprócz uzyskania informacji o procesorze (z którym nic nie robimy) synchronizuje bufor wykonawczy procesora tak, aby terminy nie były uzależnione od realizacji poza zleceniem.
  • wykonuje wykonanie rdtsc (read timestamp). To ściąga liczba cykle maszynowe wykonywane od czasu resetowania procesora. To jest 64-bit wartość, więc przy obecnych prędkościach procesora będzie owijać się co około 194 lata. Co ciekawe, w oryginalnym Pentium reference zauważają, że owija się wokół każdego Około 5800 lat.
  • ostatnia para linii przechowuje wartości z rejestrów do zmienne hi I lo i umieścić to w 64-bitowej wartości zwrotnej.

Uwagi szczegółowe:

  • Realizacja poza zleceniem może spowodować nieprawidłowe wyniki, więc wykonujemy Instrukcja "cpuid", która oprócz podania pewnych informacji o cpu synchronizuje również wszelkie out-of-order wykonania instrukcji.

  • Większość OS ' ów synchronizuje liczniki na procesorach po ich uruchomieniu, więc odpowiedź jest dobra w ciągu kilku nano-sekund.

  • Komentarz hibernacyjny jest chyba prawdziwy, ale w praktyce można pewnie nie obchodzi mnie czas hibernacji granice.

  • Co do speedstep: nowsze procesory Intela zmienia i zwraca skorygowaną liczbę. Zrobiłem Szybki skan niektóre z pudełek w naszej sieci i znalazł tylko jedno pudełko, które nie miałem: Pentium 3 z jakimś starym serwerem bazodanowym. (to są linuksowe pudełka, więc sprawdziłem: grep constant_tsc / proc / cpuinfo)

  • Nie jestem pewien co do procesorów AMD, jesteśmy przede wszystkim sklepem Intela, chociaż znam kilku naszych Guru systemów niskiego poziomu czy Ocena AMD.

Mam nadzieję, że to zaspokoi twoją ciekawość, to ciekawe i (IMHO) niedouczony obszar programowania. Wiesz, kiedy Jeff i Joel byli mówiąc o tym, czy programista powinien znać C? Byłem krzycząc na nich: "Hej, zapomnij o tym wysokim poziomie C... asembler jest to, czego powinieneś się nauczyć, jeśli chcesz wiedzieć, czym jest komputer robi!"

 18
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-15 06:44:06

Być może zainteresuje cię Linux FAQ dla clock_gettime(CLOCK_REALTIME)

 14
Author: David Schlosnagle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-07 23:04:40

Wine używa gettimeofday() do implementacji funkcji QueryPerformanceCounter() i wiadomo, że wiele gier z systemem Windows działa na Linuksie i Macu.

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

Prowadzi do http://source.winehq.org/source/dlls/ntdll/time.c#L448

 11
Author: Vincent Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-04 14:44:56

Więc mówi wprost mikrosekundy, ale mówi, że rozdzielczość zegara systemowego jest nieokreślona. Przypuszczam, że rozdzielczość w tym kontekście oznacza, jak najmniejsza kwota zostanie kiedykolwiek zwiększona?

Struktura danych jest zdefiniowana jako posiadanie mikrosekund jako jednostki miary, ale to nie znaczy, że zegar lub system Operacyjny jest w stanie dokładnie mierzyć.

Jak sugerowali inni, gettimeofday() jest złe, ponieważ ustawienie czasu może spowodować zegar przekręcić i odrzucić obliczenia. clock_gettime(CLOCK_MONOTONIC) jest tym, czego chcesz, i clock_getres() powie Ci precyzję zegara.

 10
Author: Joe Shaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 04:39:01

Rzeczywista rozdzielczość gettimeofday() zależy od architektury sprzętowej. Procesory Intel, jak również maszyny SPARC oferują timery o wysokiej rozdzielczości, które mierzą mikrosekundy. Inne architektury sprzętowe wracają do timera systemu, który jest zwykle ustawiony na 100 Hz. W takich przypadkach rozdzielczość czasu będzie mniej dokładna.

ODPOWIEDŹ uzyskałem z pomiar czasu wysokiej rozdzielczości i Timery, część i

 9
Author: CodingWithoutComments,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 18:12:53

Z mojego doświadczenia i z tego, co czytałem w Internecie, odpowiedź brzmi "Nie", Nie jest gwarantowana. Zależy to od szybkości procesora, systemu operacyjnego, Linuksa itp.

 5
Author: CodingWithoutComments,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-01 15:01:13

Ta ODPOWIEDŹ wspomina o problemach z regulacją zegara. Zarówno problemy związane z poprawką czasu, jak i problemy z poprawką czasu są rozwiązywane w C++11 za pomocą biblioteki <chrono>.

Zegar std::chrono::steady_clock jest gwarantowany, że nie będzie regulowany, a ponadto będzie postępował ze stałą prędkością w stosunku do czasu rzeczywistego, więc technologie takie jak SpeedStep nie mogą na niego wpływać.

Możesz uzyskać typy jednostek poprzez konwersję do jednej ze specjalizacji std::chrono::duration, takich jak std::chrono::microseconds. W przypadku tego typu nie ma niejasności co do jednostek używanych przez wartość tick. Należy jednak pamiętać, że zegar nie musi mieć tej rozdzielczości. Można przekonwertować czas trwania na attosekundy bez tak dokładnego zegara.

 5
Author: bames53,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:37

Odczyt RDTSC nie jest niezawodny w systemach SMP, ponieważ każdy procesor utrzymuje swój własny licznik i każdy licznik nie jest gwarantowany przez zsynchronizowany z innym procesorem.

Proponuję spróbować clock_gettime(CLOCK_REALTIME). Podręcznik posix wskazuje, że powinno to być zaimplementowane na wszystkich zgodnych systemach. Może zapewnić liczbę nanosekund, ale prawdopodobnie będziesz chciał sprawdzić clock_getres(CLOCK_REALTIME) w systemie, aby zobaczyć, jaka jest rzeczywista rozdzielczość.

 3
Author: Doug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-07 23:05:44