Mierz czas w Linuksie - czas vs zegar vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?


148

Wśród funkcji czasowych, time, clock getrusage, clock_gettime, gettimeofdayi timespec_getchcę, aby jasno zrozumieć, w jaki sposób są one realizowane i jakie są ich wartości zwracane w celu poznania, w którym sytuacja muszę ich używać.

Najpierw musimy sklasyfikować funkcje zwracające wartości zegara ściennego względem funkcji zwracających wartości procesów lub wątków . gettimeofdayzwraca wartość zegara ściennego, clock_gettimezwraca wartość zegara lub wartości procesu lub wątków w zależności od Clockprzekazanego mu parametru. getrusagei clockzwracają wartości procesu.

Następnie drugie pytanie dotyczy realizacji tych funkcji, aw konsekwencji ich dokładności. Z jakiego mechanizmu sprzętowego lub programowego korzystają te funkcje.

Wygląda na to, że getrusageużywa tylko tiku jądra (zwykle 1 ms) i w konsekwencji nie może być dokładniejszy niż ms. Czy to jest poprawne? Wtedy getimeofdayfunkcja wydaje się używać najdokładniejszego dostępnego sprzętu. W konsekwencji jego dokładność to zwykle mikrosekunda (nie może być większa z powodu API) na najnowszym sprzęcie. A co z tym clock, że strona podręcznika mówi o "przybliżeniu", co to znaczy? A co z tym clock_gettime, że API jest w nanosekundach, czy to oznacza, że ​​może być tak dokładne, jeśli pozwala na to podstawowy sprzęt? A co z monotonią?

Czy są jakieś inne funkcje?

Odpowiedzi:


198

Problem polega na tym, że w C i C ++ dostępnych jest kilka różnych funkcji czasu, a niektóre z nich różnią się zachowaniem między implementacjami. Wokół krąży również wiele pół odpowiedzi. Zestawienie listy funkcji zegara wraz z ich właściwościami pozwoliłoby poprawnie odpowiedzieć na to pytanie. Na początek zapytajmy, jakich odpowiednich właściwości szukamy. Patrząc na Twój post proponuję:

  • Jaki czas odmierza zegar? (prawdziwy, użytkownik, system lub, miejmy nadzieję, że nie, zegar ścienny?)
  • Jaka jest precyzja zegara? (s, ms, µs czy szybciej?)
  • Po jakim czasie zegar się kręci? Czy jest jakiś mechanizm, aby tego uniknąć?
  • Czy zegar jest monotoniczny, czy będzie się zmieniał wraz ze zmianami czasu systemowego (przez NTP, strefę czasową, czas letni, przez użytkownika itp.)?
  • Jak powyższe różnią się w zależności od implementacji?
  • Czy dana funkcja jest przestarzała, niestandardowa itp.?

Zanim zacznę listę, chciałbym zwrócić uwagę, że zegar ścienny rzadko jest odpowiednim czasem do użycia, podczas gdy zmienia się wraz ze zmianami strefy czasowej, zmianami czasu letniego lub jeśli zegar ścienny jest synchronizowany przez NTP. Żadna z tych rzeczy nie jest dobra, jeśli poświęcasz czas na planowanie wydarzeń lub porównywanie wydajności. To naprawdę dobre tylko dla tego, co mówi nazwa, zegara na ścianie (lub pulpicie).

Oto, co do tej pory znalazłem dla zegarów w systemie Linux i OS X:

  • time() zwraca czas zegara ściennego z systemu operacyjnego z dokładnością do sekund.
  • clock()wydaje się zwracać sumę czasu użytkownika i systemu. Jest obecny w C89 i późniejszych. Kiedyś miał to być czas procesora w cyklach, ale współczesne standardy, takie jak POSIX, wymagają, aby CLOCKS_PER_SEC wynosił 1000000, co daje maksymalną możliwą precyzję 1 µs. Dokładność w moim systemie rzeczywiście wynosi 1 µs. Ten zegar zawija się po osiągnięciu szczytu (zwykle dzieje się to po ~ 2 ^ 32 tyknięciach, co nie jest zbyt długie dla zegara 1 MHz). man clockmówi, że od wersji 2.18 glibc jest zaimplementowany clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)w Linuksie.
  • clock_gettime(CLOCK_MONOTONIC, ...)zapewnia rozdzielczość nanosekundową, jest monotoniczny. Uważam, że „sekundy” i „nanosekundy” są przechowywane oddzielnie, każdy w 32-bitowych licznikach. W ten sposób każde zawijanie nastąpiłoby po wielu dziesiątkach lat bezawaryjnej pracy. Wygląda to na bardzo dobry zegar, ale niestety nie jest jeszcze dostępny na OS X. POSIX 7 opisuje CLOCK_MONOTONICjako opcjonalne rozszerzenie .
  • getrusage()okazał się najlepszym wyborem w mojej sytuacji. Zgłasza czasy użytkownika i systemu oddzielnie i nie zawija się. Precyzja w moim systemie wynosi 1 µs, ale testowałem ją również na systemie Linux (Red Hat 4.1.2-48 z GCC 4.1.2) i tam precyzja wynosiła tylko 1 ms.
  • gettimeofday()zwraca czas zegara ściennego z (nominalną) dokładnością µs. W moim systemie zegar wydaje się mieć dokładność µs, ale nie jest to gwarantowane, ponieważ „rozdzielczość zegara systemowego zależy od sprzętu” . POSIX.1-2008 tak mówi . „Aplikacje powinny używać clock_gettime()funkcji zamiast przestarzałej gettimeofday()funkcji”, więc należy trzymać się od niej z daleka. Linux x86 i implementuje go jako wywołanie systemowe .
  • mach_absolute_time()jest opcją dla taktowania w bardzo wysokiej rozdzielczości (ns) w systemie OS X. W moim systemie to rzeczywiście daje rozdzielczość ns. W zasadzie ten zegar zawija się, jednak przechowuje ns przy użyciu 64-bitowej liczby całkowitej bez znaku, więc zawijanie nie powinno stanowić problemu w praktyce. Przenośność jest wątpliwa.
  • Napisałem funkcję hybrydową opartą na tym fragmencie, który używa clock_gettime podczas kompilacji w systemie Linux lub timera Macha podczas kompilacji w systemie OS X, aby uzyskać precyzję ns zarówno w systemie Linux, jak i OS X.

Wszystkie powyższe istnieją zarówno w systemie Linux, jak i OS X, chyba że określono inaczej. „Mój system” w powyższym to Apple z systemem OS X 10.8.3 z GCC 4.7.2 z MacPorts.

Na koniec, oprócz powyższych linków, jest lista odniesień, które uznałem za pomocne:


Aktualizacja : dla OS X, clock_gettimezostała wdrożona od 10.12 (Sierra). Ponadto platformy oparte na POSIX i BSD (takie jak OS X) współużytkują rusage.ru_utimepole struktur.


Mac OS X nie ma clock_gettime, stąd zastosowanie gettimeofday()bycia nieco bardziej wszechstronnym niżclock_gettime()
bobobobo

1
Nie wspomniałeś times()(z s), które istniało w POSIX od wydania 1. Odnośnie GNU / Linuksa: Zgodnie ze stroną podręcznika clock (3), clock()od glibc 2.17 i wcześniejszych zostało zaimplementowanych na wierzchu, ale dla ulepszenia precyzja, jest teraz zaimplementowana na szczycie clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...), co jest również określone w POSIX, ale jest opcjonalne.
vinc17

2
@starflyer Precyzja zegara jest częściowo ograniczona ilością czasu potrzebnego do odpytania zegara. Dzieje się tak, ponieważ jeśli wywołam zegar i powrót zajmie 1 µs, to czas, w którym raport zegara będzie „wyłączony” o 1 µs z perspektywy dzwoniącego. Oznacza to, że bardzo dokładny zegar musi również charakteryzować się małym opóźnieniem. Zwykle więc nie ma kompromisu, o którym mówisz: najtańsze zegary będą również najdokładniejsze.
Douglas B. Staple

3
Również większość zegarów nie dba o czas / strefy czasowe czasu letniego, nawet jeśli są uważane za zegary ścienne . Oba timei gettimeofdaypowracają, przynajmniej obecnie, sekundy od epoki (aka unix-timestamp). Jest to niezależne od stref czasowych / czasu letniego. Sekundy przestępne to inna historia ...
Zulan

2
Dla użytkowników Androida używanie CLOCK_MONOTONIC może być problematyczne, ponieważ aplikacja może zostać zawieszona wraz z zegarem. W tym celu Android dodał licznik czasu ANDROID_ALARM_ELAPSED_REALTIME, który jest dostępny przez ioctl. niektóre informacje na temat tych i innych informacji związanych z zawieszeniem można znaleźć tutaj
Itay Bianco.

17

C11 timespec_get

Przykład użycia pod adresem : https://stackoverflow.com/a/36095407/895245

Maksymalna możliwa zwracana precyzja to nanosekundy, ale rzeczywista precyzja jest zdefiniowana w ramach implementacji i może być mniejsza.

Zwraca czas ściany, a nie użycie procesora.

glibc 2.21 implementuje go pod sysdeps/posix/timespec_get.ci przekazuje bezpośrednio do:

clock_gettime (CLOCK_REALTIME, ts) < 0)

clock_gettimei CLOCK_REALTIMEsą POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html i man clock_gettimemówi, że ta miara może mieć nieciągłości, jeśli zmienisz niektóre ustawienia czasu systemowego podczas działania programu.

C ++ 11 chrono

Skoro już o tym mowa, omówmy je również: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (C ++ stdlib znajduje się wewnątrz źródła GCC):

  • high_resolution_clock jest aliasem dla system_clock
  • system_clock przechodzi do pierwszej z dostępnych opcji:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock przechodzi do pierwszej z dostępnych opcji:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Pytanie: Różnica między std :: system_clock i std :: steady_clock?

CLOCK_REALTIMEvs CLOCK_MONOTONIC: różnica między CLOCK_REALTIME i CLOCK_MONOTONIC?


1
Świetna odpowiedź, która demistyfikuje typowe implementacje. Właśnie to ludzie naprawdę powinni wiedzieć.
Celess
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.