Misurare il tempo in Linux – tempo vs orologio vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?

Tra le funzioni di cronometraggio, time , clock getrusage , clock_gettime , gettimeofday e timespec_get , voglio capire chiaramente come sono implementate e quali sono i loro valori di ritorno per sapere in quale situazione devo usarli.

Per prima cosa dobbiamo classificare le funzioni che restituiscono i valori del wall-clock confrontati con le funzioni che restituiscono i valori del processo o dei thread . gettimeofday restituisce il valore del wall-clock, clock_gettime restituisce il valore wall-clock o process o i valori dei thread in base al parametro Clock passato ad esso. getrusage valori di processo di getrusage e clock return.

Quindi la seconda domanda riguarda l’implementazione di queste funzioni e, di conseguenza, la loro accuratezza. Quale meccanismo hardware o software utilizza queste funzioni.

Sembra che la getrusage usi solo il tick del kernel (di solito lungo 1ms) e di conseguenza non può essere più preciso del ms. È giusto? Quindi la funzione getimeofday sembra utilizzare l’hardware sottostante più preciso disponibile. Di conseguenza, la precisione è solitamente il microsecondo (non può essere più a causa dell’API) sull’hardware recente. Che dire clock , la pagina man parla di “approssimazione”, cosa significa? Che dire di clock_gettime , l’API è in nanosecondi, vuol dire che è in grado di essere così preciso se l’hardware sottostante lo consente? Che dire della monotonicità?

Ci sono altre funzioni?

Il problema è che ci sono diverse funzioni temporali disponibili in C e C ++, e alcune di esse variano nel comportamento tra le implementazioni. Ci sono anche molte mezze risposte in giro. Compilare un elenco di funzioni di orologio insieme alle loro proprietà avrebbe risposto correttamente alla domanda. Per iniziare chiediamo quali sono le proprietà rilevanti che stiamo cercando. Osservando il tuo post, suggerisco:

  • Che ora viene misurata dall’orologio? (reale, utente, sistema, o, si spera, orologio da muro?)
  • Qual è la precisione dell’orologio? (s, ms, μs o più veloce?)
  • Dopo quanto tempo avvolge l’orologio? O c’è qualche meccanismo per evitarlo?
  • L’orologio è monotono o cambierà con i cambiamenti nell’ora del sistema (tramite NTP, fuso orario, ora legale, dall’utente, ecc.)?
  • In che modo le differenze di cui sopra variano tra le implementazioni?
  • La funzione specifica è obsoleta, non standard, ecc.?

Prima di iniziare la lista, vorrei sottolineare che l’orario di wall-clock è raramente il momento giusto da usare, mentre cambia con le modifiche del fuso orario, le modifiche all’ora legale o se l’orologio da parete è sincronizzato da NTP. Nessuna di queste cose è utile se si utilizza il tempo per pianificare eventi o per eseguire il benchmark delle prestazioni. È davvero buono solo per quello che dice il nome, un orologio sul muro (o sul desktop).

Ecco cosa ho trovato finora per gli orologi in Linux e OS X:

  • time() restituisce l’ora del wall-clock dal sistema operativo, con precisione in secondi.
  • clock() sembra restituire la sum di utente e ora di sistema. È presente nella C89 e successive. Un tempo questo doveva essere il tempo di CPU in cicli, ma gli standard moderni come POSIX richiedono CLOCKS_PER_SEC di essere 1000000, dando una precisione massima ansible di 1 μs. La precisione sul mio sistema è infatti di 1 μs. Questo orologio si avvolge una volta terminato (ciò accade normalmente dopo ~ 2 ^ 32 tick, che non è molto lungo per un orologio da 1 MHz). man clock dice che poiché glibc 2.18 è implementato con clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) in Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...) fornisce una risoluzione di nanosecondi, è monotona. Credo che i “secondi” e i “nanosecondi” siano memorizzati separatamente, ciascuno in contatori a 32 bit. Quindi, qualsiasi avvolgimento si sarebbe verificato dopo molte dozzine di anni di operatività. Questo sembra un ottimo orologio, ma sfortunatamente non è ancora disponibile su OS X. POSIX 7 descrive CLOCK_MONOTONIC come estensione opzionale .
  • getrusage() si è rivelata la scelta migliore per la mia situazione. Riporta separatamente gli orari dell’utente e del sistema e non si avvolge. La precisione del mio sistema è di 1 μs, ma l’ho anche testata su un sistema Linux (Red Hat 4.1.2-48 con GCC 4.1.2) e lì la precisione era solo di 1 ms.
  • gettimeofday() restituisce il tempo di wall-clock con precisione (nominalmente) μs. Sul mio sistema questo orologio sembra avere precisione μ, ma questo non è garantito, perché “la risoluzione dell’orologio di sistema dipende dall’hardware” . POSIX.1-2008 lo dice . “Le applicazioni dovrebbero usare la funzione clock_gettime() invece della funzione gettimeofday() “, quindi dovresti starne alla larga. Linux x86 e lo implementa come una chiamata di sistema .
  • mach_absolute_time() è un’opzione per la temporizzazione ad altissima risoluzione (ns) su OS X. Sul mio sistema, questo effettivamente fornisce una risoluzione ns. In linea di principio questo orologio si avvolge, tuttavia sta memorizzando ns usando un numero intero senza segno a 64 bit, quindi l’involucro non dovrebbe essere un problema nella pratica. La portabilità è discutibile.
  • Ho scritto una funzione ibrida basata su questo frammento che usa clock_gettime quando è compilato su Linux, o un timer Mach quando compilato su OS X, al fine di ottenere precisione ns sia su Linux che OS X.

Tutto quanto sopra esiste sia in Linux che in OS X tranne dove diversamente specificato. “Il mio sistema” di cui sopra è un Apple che esegue OS X 10.8.3 con GCC 4.7.2 da MacPorts.

Infine, ecco un elenco di riferimenti che ho trovato utili in aggiunta ai link sopra:


Aggiornamento : per OS X, clock_gettime è stato implementato a partire da 10.12 (Sierra). Inoltre, entrambe le piattaforms basate su POSIX e BSD (come OS X) condividono il campo struct rusage.ru_utime .

C11 timespec_get

Esempio di utilizzo: https://stackoverflow.com/a/36095407/895245

La massima precisione ansible restituita è di nanosecondi, ma la precisione effettiva è definita dall’implementazione e potrebbe essere più piccola.

Restituisce il tempo di parete, non l’utilizzo della CPU.

glibc 2.21 lo implementa sotto sysdeps/posix/timespec_get.c e inoltra direttamente a:

 clock_gettime (CLOCK_REALTIME, ts) < 0) 

clock_gettime e CLOCK_REALTIME sono POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html e man clock_gettime dice che questa misura potrebbe avere delle discontinuità se si modificano alcune impostazioni di tempo del sistema durante l'esecuzione del programma.

C ++ 11 chrono

Visto che ci siamo, copriamoli pure: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (lo stdlib C ++ è contenuto nella sorgente GCC):

  • high_resolution_clock è un alias per system_clock
  • system_clock inoltra al primo dei seguenti che è disponibile:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock avanti al primo dei seguenti che è disponibile:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Alla domanda: Differenza tra std :: system_clock e std :: steady_clock?

CLOCK_REALTIME vs CLOCK_MONOTONIC : differenza tra CLOCK_REALTIME e CLOCK_MONOTONIC?