Różnica między CLOCK_REALTIME a CLOCK_MONOTONIC?

206

Czy mógłby pan wyjaśnić różnicę między CLOCK_REALTIMEi CLOCK_MONOTONICzegary zwracane przez clock_gettime()Linux?

Który jest lepszy wybór, jeśli muszę obliczyć upływ czasu między znacznikami czasu wytworzonymi przez źródło zewnętrzne a bieżącym czasem?

Wreszcie, jeśli mam demona NTP okresowo dostosowującego czas systemowy, w jaki sposób te dostosowania oddziałują z każdym z nich CLOCK_REALTIMEi CLOCK_MONOTONIC?

NPE
źródło

Odpowiedzi:

238

CLOCK_REALTIMEreprezentuje najlepsze przypuszczenie maszyny o bieżącym zegarze ściennym, pora dnia. Jak mówią Ignacio i MarkR , oznacza to, że CLOCK_REALTIMEmoże przeskakiwać do przodu i do tyłu w miarę zmiany systemowego zegara czasu, w tym przez NTP.

CLOCK_MONOTONICreprezentuje bezwzględny czas, jaki upłynął od zegara ściennego od pewnego dowolnego, stałego punktu w przeszłości. Nie ma na to wpływu zmiany systemowego zegara czasu.

Jeśli chcesz obliczyć czas, jaki upłynął między dwoma zdarzeniami zaobserwowanymi na jednej maszynie bez pośredniego restartu, CLOCK_MONOTONICjest najlepszą opcją.

Zauważ, że w Linuksie CLOCK_MONOTONICnie mierzy czasu spędzonego na zawieszeniu, chociaż zgodnie z definicją POSIX powinno to robić. Możesz użyć specyficznego CLOCK_BOOTTIMEdla Linuksa zegara monotonicznego, który działa podczas zawieszenia.

caf
źródło
11
Zauważ, że w nowszych jądrach dostępny jest CLOCK_MONOTONIC_RAW, co jest jeszcze lepsze (bez zmian NTP).
Joseph Garvin,
14
@JosephGarvin dla pewnej wartości „lepszej”, być może - CLOCK_MONOTONIC_RAW może działać szybko lub wolno w czasie rzeczywistym o kilka (lub kilkaset) części na milion, a jego szybkość może się różnić w zależności od warunków otoczenia, takich jak temperatura lub napięcie (lub czas kradzieży na wirtualne maszyny). Na prawidłowo działającej maszynie NTP dokłada wszelkich starań, aby złagodzić wszystkie te czynniki, dzięki czemu CLOCK_MONOTONIC dokładniej odzwierciedla prawdziwy upływ czasu.
hobbs
23
To prawda, że ​​może być interesujący mieć CLOCK_MONOTONIC_PARBOILED, na który wpływ miały wysiłki NTP w celu skorygowania błędów częstotliwości, ale nie wpływają one na jego wysiłki w celu skorygowania błędów fazy, ale jest to bardzo skomplikowane dla wątpliwego wzmocnienia :)
hobbs
1
Podoba mi się punkt, który porusza @hobbs. Co jeśli martwisz się programami, na które może wpływać przesunięcie zegara? Byłby CLOCK_MONOTONICnajlepszy wybór w tym scenariuszu? np. Patriot Missile System
sjagr
3
Myślę, że należy również wspomnieć, że na CLOCK_REALTIME wpływ mają sekundy przestępne. Oznacza to, że będzie generował podwójne znaczniki czasu za każdym razem, gdy wstawiany jest sekunda przestępna. Ostatnim razem stało się to 30 czerwca 2012 r. I sporo oprogramowania miało problemy .
user1202136
38

Książka Roberta Love'a LINUX System Programming 2nd Edition , szczególnie odnosi się do twojego pytania na początku rozdziału 11, str. 363:

Ważnym aspektem monotonicznego źródła czasu NIE jest bieżąca wartość, ale gwarancja, że ​​źródło czasu rośnie ściśle liniowo, a zatem jest przydatne do obliczania różnicy czasu między dwoma próbkami

To powiedziawszy, uważam, że zakłada, że ​​procesy działają na tej samej instancji systemu operacyjnego, więc możesz chcieć mieć okresową kalibrację, aby móc oszacować dryft.

użytkownik2548100
źródło
25

CLOCK_REALTIMEma wpływ NTP i może poruszać się do przodu i do tyłu. CLOCK_MONOTONICnie jest i przesuwa się o jeden tik na tyknięcie.

Ignacio Vazquez-Abrams
źródło
15
Na CLOCK_MONOTONIC wpływa zmiana czasu NTP (zmiana czasu). Jednak nie skacze.
derobert
3
Ale w nowszych jądrach występuje CLOCK_MONOTONIC_RAW, na który tak naprawdę NTP nie ma wpływu.
Joseph Garvin,
1
„tik” - jakiś szorstki pomysł na to, jak duże / długie / procesorowe instrukcje są zaznaczone na Linux / amd64? Lub gdzie mogę uzyskać dokumenty na którekolwiek z tych zagadnień?
kevinarpe
@kevinarpe Nie jestem pewien, ale myślę, że tik jest definiowany jako ułamek czasu, a nie liczba cykli procesora, często wynosi 1/100 sekundy.
Stéphane
@ Stéphane: Z pewnością muszę być ciaśniejszy niż 10ms. Myślę, że Java System.nanoTime()używa CLOCK_MONOTONICi może mierzyć czas trwania 1000ns lub mniej. Może myślisz o czasie systemowym, który czasem ogranicza się do milisekund?
kevinarpe
20

Oprócz odpowiedzi Ignacio , CLOCK_REALTIMEmoże skakać do przodu, a czasami do tyłu. CLOCK_MONOTONICnie robi ani; po prostu idzie naprzód (chociaż prawdopodobnie resetuje się przy ponownym uruchomieniu).

Solidna aplikacja musi być w stanie tolerować CLOCK_REALTIMEprzeskakiwanie do przodu od czasu do czasu (i być może bardzo nieznacznie do tyłu bardzo rzadko, chociaż jest to raczej przypadek na krawędzi).

Wyobraź sobie, co dzieje się, gdy zawieszasz laptopa - CLOCK_REALTIMEprzeskakuje do przodu po wznowieniu, CLOCK_MONOTONICnie robi tego. Wypróbuj na maszynie wirtualnej.

MarkR
źródło
3
CLOCK_MONOTONIC zaczyna się od 0, kiedy program się uruchamia; nie jest przeznaczony do użytku międzyprocesowego.
Benubird
18
@Benubird: Nie zaczyna się od 0, gdy program się uruchamia. To CLOCK_PROCESS_CPUTIME_ID. Szybki test: $ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279. Liczba ta odpowiada czasowi pracy systemu w Linuksie, ale standard mówi, że jest arbitralny.
derobert
4
Nawiasem mówiąc, nie sądzę, aby zachowanie Linuksa, w którym CLOCK_MONOTONICzatrzymywanie się po zawieszeniu / wznowieniu było zgodne z POSIX. Powinien to być czas od ustalonego punktu w przeszłości, ale zatrzymanie zegara przed zawieszeniem / wznowieniem to przerywa.
caf
15

Cytaty POSIX 7

POSIX 7 określa oba na stronie http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html :

CLOCK_REALTIME:

Ten zegar reprezentuje zegar mierzący w czasie rzeczywistym system. Dla tego zegara wartości zwrócone przez clock_gettime () i określone przez clock_settime () reprezentują ilość czasu (w sekundach i nanosekundach) od Epoki.

CLOCK_MONOTONIC (funkcja opcjonalna):

W przypadku tego zegara wartość zwracana przez clock_gettime () reprezentuje ilość czasu (w sekundach i nanosekundach) od nieokreślonego punktu w przeszłości (na przykład czas uruchomienia systemu lub Epoka). Ten punkt nie zmienia się po czasie uruchomienia systemu. Wartości zegara CLOCK_MONOTONIC nie można ustawić za pomocą clock_settime ().

clock_settime()daje ważną wskazówkę: systemy POSIX są w stanie dowolnie się CLOCK_REALITMEz tym zmieniać , więc nie polegaj na tym, że płynie ani w sposób ciągły, ani do przodu. NTP może być zaimplementowany przy użyciu clock_settime()i może tylko wpływać CLOCK_REALITME.

Implementacja jądra Linuksa wydaje się wymagać czasu rozruchu jako epoki dla CLOCK_MONOTONIC: Punkt wyjścia dla CLOCK_MONOTONIC

Ciro Santilli
źródło
0

Przepraszamy, brak reputacji, aby dodać to jako komentarz. Jest to więc odpowiedź uzupełniająca.

W zależności od tego, jak często będziesz dzwonić clock_gettime(), powinieneś pamiętać, że tylko niektóre „zegary” są dostarczane przez Linux w VDSO (tj. Nie wymagają wywołania systemowego z całym narzutem jednego - co pogorszyło się dopiero po dodaniu Linuksa obrony przed atakami typu Widm).

Chociaż clock_gettime(CLOCK_MONOTONIC,...), clock_gettime(CLOCK_REALTIME,...)i gettimeofday()zawsze będą bardzo szybkie (przyspieszane przez VDSO), nie jest to prawdą, na przykład dla CLOCK_MONOTONIC_RAW lub jakiegokolwiek innego zegara POSIX.

Można to zmienić w zależności od wersji jądra i architektury.

Chociaż większość programów nie musi zwracać na to uwagi, mogą występować skoki opóźnienia w zegarach przyspieszanych przez VDSO: jeśli trafisz je dokładnie, gdy jądro aktualizuje obszar pamięci współużytkowanej z licznikami zegarów, musi poczekać na jądro do końca.

Oto „dowód” (GitHub, aby trzymać boty z dala od kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7

anonimowy
źródło