2012-09-12 26 views
114

Wśród funkcji czasowych, time, clockgetrusage, clock_gettime, gettimeofday i timespec_get, chcę 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ć.Zmierz czas w Linuksie - czas vs zegar vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?

Najpierw musimy zaklasyfikować funkcje wracające ściennego zegara wartościami porównać do funkcji powracających proces lub nitek ceni. gettimeofday zwraca wartość zegara ściennego, clock_gettime zwraca wartość zegara ściennego lub wartości procesów lub wątków w zależności od przekazanego do niego parametru Clock. getrusage i clock zwracają wartości procesowe.

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

Wygląda na to, że getrusage używa tylko znacznika jądra (zwykle o długości 1 ms), aw konsekwencji nie może być dokładniejszy niż ms. Czy to jest poprawne? Następnie funkcja getimeofday wydaje się używać najdokładniejszego dostępnego sprzętu bazowego. W konsekwencji jego dokładność jest zwykle mikrosekundą (nie może być większa z powodu API) na ostatnim sprzęcie. Co o clock, strona man mówi o "przybliżeniu", co to znaczy? A co z clock_gettime, interfejs API znajduje się w nanosekundzie, co oznacza, że ​​może być tak dokładny, jeśli pozwala na to sprzęt podrzędny? A co z monotonicznością?

Czy są jeszcze jakieś inne funkcje?

Odpowiedz

150

Problem polega na tym, że w językach C i C++ dostępnych jest kilka różnych funkcji czasowych, a niektóre z nich różnią się pod względem zachowania między implementacjami. Istnieje również wiele mniejszych odpowiedzi. Kompilacja listy funkcji zegara wraz z ich właściwościami odpowiedziałaby poprawnie na pytanie. Na początek zapytaj, jakie są odpowiednie właściwości, których szukamy. Patrząc na twój post, proponuję:

  • Jaką godzinę mierzy zegar? (prawdziwy, użytkownik, system, lub, mam nadzieję, nie, zegar ścienny?)
  • Jaka jest dokładność zegara? (s, ms, μs, lub szybciej?)
  • Po upływie czasu, jaki upłynął od czasu do czasu? Czy istnieje jakiś mechanizm, aby tego uniknąć?
  • Czy zegar jest monotoniczny, czy też ulegnie zmianie wraz ze zmianami czasu systemowego (przez NTP, strefę czasową, czas letni, przez użytkownika itd.)?
  • Czym różnią się powyższe implementacje?
  • Czy określona funkcja jest przestarzała, niestandardowa itp.?

Przed uruchomieniem tej listy, chciałbym zwrócić uwagę, że czas na zegary rzadko jest właściwym czasem, podczas gdy zmienia się wraz ze zmianami stref czasowych, zmianami czasu letniego lub zegarem ściennym. zsynchronizowane przez NTP. Żadna z tych rzeczy nie jest dobra, jeśli wykorzystujesz czas na planowanie wydarzeń lub porównywanie wydajności. Jest naprawdę dobry tylko na to, co mówi nazwa, zegar na ścianie (lub na pulpicie).

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

  • time() zwraca upływ czasu od systemu operacyjnego, z dokładnością do sekundy.
  • clock() wydaje się zwracać sumę czasu użytkownika i systemu. Jest obecny w C89 i później. W pewnym momencie miał to być czas procesora w cyklach, ale nowoczesne standardy wymagają, aby wartość CLOCKS_PER_SEC wynosiła 1000000, dając maksymalną możliwą dokładność wynoszącą 1 μs. Dokładność w moim systemie wynosi rzeczywiście 1 μs. Ten zegar owija się, gdy się topi (dzieje się to zazwyczaj po ~ 2^32 taktach, co nie jest zbyt długie dla zegara 1 MHz). man clock mówi, że ponieważ glibc 2.18 jest zaimplementowany z clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) w systemie Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...) zapewnia rozdzielczość nanosekundową, jest monotoniczna. Uważam, że "sekundy" i "nanosekundy" są przechowywane oddzielnie, każde w 32-bitowych licznikach. Tak więc każde zawinięcie nastąpi po kilkudziesięciu latach przestoju. Wygląda to na bardzo dobry zegar, ale niestety nie jest jeszcze dostępny na OS X. POSIX 7 describes CLOCK_MONOTONIC as an optional extension.
  • getrusage() okazało się najlepszym wyborem w mojej sytuacji. Raportuje oddzielnie czasy użytkowników i systemu i nie zawija się. Precyzja w moim systemie wynosi 1 μs, ale testowałem go również w 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 precyzją (nominalnie) μs. W moim systemie ten zegar wydaje się mieć dokładność μs, ale nie jest to gwarantowane, ponieważ "the resolution of the system clock is hardware dependent". POSIX.1-2008 says that. "Aplikacje powinny używać funkcji clock_gettime() zamiast przestarzałej funkcji gettimeofday()", więc powinieneś trzymać się z dala od niej. Linux x86 i implementuje go jako as a system call.
  • mach_absolute_time() to opcja dla synchronizacji w bardzo wysokiej rozdzielczości (ns) w systemie OS X. W moim systemie to rzeczywiście daje rozdzielczość ns. W zasadzie ten zegar owija się, ale zapisuje ns używając 64-bitowej liczby całkowitej bez znaku, więc zawijanie nie powinno stanowić problemu w praktyce. Przenośność jest wątpliwa.
  • I wrote a hybrid function podstawie this snippet który wykorzystuje clock_gettime gdy kompilowany na Linux lub czasowy Mach gdy kompilowany na OS X, w celu uzyskania precyzji ns zarówno na Linux i OS X.

Wszystkie powyższe istnieje w zarówno Linux, jak i OS X, chyba że określono inaczej. "Mój system" w powyższym jest Apple z systemem OS X 10.8.3 z GCC 4.7.2 z MacPorts.

Wreszcie, tutaj jest lista referencji, które znalazłem pomocne w uzupełnieniu do powyższych linków:


Aktualizacja: dla OS X, clock_gettime została wprowadzona od 10.12 (Sierra). Również platformy oparte na POSIX i BSD (jak OS X) mają wspólne pole strukturalne rusage.ru_utime.

+1

masz teraz 18 punktów rep ;-) –

+0

Mac OS X nie posiada 'clock_gettime', stąd użycie [ 'gettimeofday()'] (http://www.songho.ca/misc/timer/timer.html) jest nieco bardziej wszechstronny niż 'clock_gettime()' – bobobobo

+0

@bobobobo Zgadzam się, że OS X nie ma clock_gettime (), jednak gettimeofday() niestety mierzy czas zegara ściennego. Zaktualizowałem swój post, aby podać te informacje. Jeśli wystarczająca jest precyzja ms, polecam getrusage() jako najlepszy zegar do użycia jako timer. –

12

C11 przykład timespec_get

Wykorzystanie w: https://stackoverflow.com/a/36095407/895245

Maksymalna możliwa precyzyjna zwrócony jest nanosekund, ale rzeczywista precyzja jest realizacja zdefiniowane i może być mniejsza.

Powoduje zwrócenie czasu ściany, a nie użycia procesora.

glibc 2.21 wdraża je na sysdeps/posix/timespec_get.c i przekazuje bezpośrednio do:

clock_gettime (CLOCK_REALTIME, ts) < 0) 

clock_gettime i CLOCK_REALTIME są POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html i man clock_gettime mówi, że środek ten może mieć nieciągłości jeśli zmienisz ustawienie podczas swoich tras programowych jakiś czas systemowy .

C++ 11 Chrono

Skoro już przy tym jesteśmy, niech ich pokrycie, a także: http://en.cppreference.com/w/cpp/chrono

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

  • high_resolution_clock to pseudonim dla system_clock
  • system_clock przekazuje do pierwszego z następujących elementów, które są dostępne:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock przodu do pierwszego z następujących, które są dostępne:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

zadawane w: Difference between std::system_clock and std::steady_clock?

CLOCK_REALTIME vs CLOCK_MONOTONIC: Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?

+1

Dziękujemy za dodanie. –