Mida el tiempo en Linux-time vs clock vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?
linux-kernel (2)
Entre las funciones de time
, time
, getrusage
clock
, getrusage
, clock_gettime
y timespec_get
, quiero entender claramente cómo se implementan y cuáles son sus valores de retorno para saber en qué situación tengo que usarlos.
Primero, debemos clasificar las funciones que devuelven los valores del reloj de pared en comparación con las funciones que devuelven el proceso o los valores de los hilos . clock_gettime
devuelve el valor del reloj de pared, clock_gettime
devuelve el valor del reloj de pared o procesa o enruta los valores dependiendo del parámetro Clock
que se le pase. getrusage
y clock
return process.
Luego, la segunda pregunta se refiere a la implementación de estas funciones y, en consecuencia, a su precisión. ¿Qué mecanismo de hardware o software usan estas funciones?
Parece que getrusage
usa solo el tick del kernel (usualmente 1ms de largo) y como consecuencia no puede ser más preciso que el ms. ¿Es correcto? Entonces la función getimeofday
parece usar el hardware subyacente más preciso disponible. Como consecuencia, su precisión suele ser de un microsegundo (no puede ser más debido a la API) en el hardware reciente. ¿Qué pasa con el clock
, la página del hombre habla de "aproximación", qué significa? ¿Qué pasa con clock_gettime
, la API está en nanosegundos, significa que puede ser tan precisa si el hardware subyacente lo permite? ¿Qué hay de la monotonicidad?
¿Hay otras funciones?
El problema es que hay varias funciones de tiempo diferentes disponibles en C y C ++, y algunas de ellas varían en el comportamiento entre las implementaciones. También hay muchas respuestas a medias flotando. La compilación de una lista de funciones del reloj junto con sus propiedades respondería la pregunta correctamente. Para empezar, preguntémonos cuáles son las propiedades relevantes que estamos buscando. Mirando su publicación, sugiero:
- ¿Qué hora mide el reloj? (real, usuario, sistema o, con suerte, no, reloj de pared?)
- ¿Cuál es la precisión del reloj? (s, ms, μs o más rápido?)
- ¿Después de cuánto tiempo se ajusta el reloj? ¿O hay algún mecanismo para evitar esto?
- ¿El reloj es monótono, o cambiará con los cambios en la hora del sistema (a través de NTP, zona horaria, horario de verano, por el usuario, etc.)?
- ¿Cómo varía lo anterior entre implementaciones?
- ¿Es la función específica obsoleta, no estándar, etc.?
Antes de comenzar la lista, me gustaría señalar que la hora del reloj de pared rara vez es el momento adecuado para usarla, mientras que cambia con los cambios de zona horaria, los cambios de horario de verano o si el reloj de pared está sincronizado por NTP. Ninguna de estas cosas es buena si usa el tiempo para programar eventos o para comparar el rendimiento. Es realmente bueno para lo que dice su nombre, un reloj en la pared (o escritorio).
Esto es lo que he encontrado hasta ahora para los relojes en Linux y OS X:
-
time()
devuelve la hora del reloj de pared del SO, con precisión en segundos. -
clock()
parece devolver la suma del usuario y la hora del sistema. Está presente en C89 y más tarde. En un momento se suponía que este era el tiempo de la CPU en ciclos, pero los estándares modernos como POSIX requieren que CLOCKS_PER_SEC sea 1000000, lo que da una precisión máxima posible de 1 μs. La precisión en mi sistema es de hecho 1 μs. Este reloj se ajusta una vez que termina (esto sucede típicamente después de ~ 2 ^ 32 tics, que no es muy largo para un reloj de 1 MHz).man clock
dice que desde glibc 2.18 se implementa conclock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)
en Linux. -
clock_gettime(CLOCK_MONOTONIC, ...)
proporciona una resolución de nanosegundos, es monotónico. Creo que los ''segundos'' y ''nanosegundos'' se almacenan por separado, cada uno en contadores de 32 bits. Por lo tanto, cualquier envoltura se produciría después de muchos años de actividad. Parece un reloj muy bueno, pero desafortunadamente todavía no está disponible en OS X. POSIX 7 describeCLOCK_MONOTONIC
como una extensión opcional . -
getrusage()
resultó ser la mejor opción para mi situación. Informa los tiempos del usuario y del sistema por separado y no se ajusta. La precisión en mi sistema es de 1 μs, pero también lo probé en un sistema Linux (Red Hat 4.1.2-48 con GCC 4.1.2) y allí la precisión fue de solo 1 ms. -
gettimeofday()
devuelve el tiempo del reloj de pared con precisión (nominalmente) μs. En mi sistema, este reloj parece tener precisión μs, pero esto no está garantizado porque gettimeofday() . POSIX.1-2008 dice eso . "Las aplicaciones deben usar la funciónclock_gettime()
lugar de la función obsoletagettimeofday()
", por lo que debe mantenerse alejado de ella. Linux x86 y lo implementa como una llamada al sistema . -
mach_absolute_time()
es una opción para sincronización de muy alta resolución (ns) en OS X. En mi sistema, esto sí da resolución ns. En principio, este reloj se ajusta, sin embargo, almacena ns con un entero sin signo de 64 bits, por lo que el ajuste no debería ser un problema en la práctica. La portabilidad es cuestionable. - Escribí una función híbrida basada en este fragmento que usa clock_gettime cuando se compila en Linux, o un temporizador Mach cuando se compila en OS X, para obtener precisión ns tanto en Linux como en OS X.
Todo lo anterior existe tanto en Linux como en OS X, excepto que se especifique lo contrario. "Mi sistema" en el cuadro anterior es una Apple que ejecuta OS X 10.8.3 con GCC 4.7.2 de MacPorts.
Finalmente, aquí hay una lista de referencias que encontré útiles además de los enlaces de arriba:
- http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time
- ¿Cómo medir el tiempo de ejecución REAL de un programa C en Linux?
- http://digitalsandwich.com/archives/27-benchmarking-misconceptions-microtime-vs-getrusage.html
- http://www.unix.com/hp-ux/38937-getrusage.html
Actualización : para OS X, clock_gettime
se implementó a partir de 10.12 (Sierra). Además, las plataformas basadas en POSIX y BSD (como OS X) comparten el campo de estructura rusage.ru_utime
.
C11 timespec_get
Ejemplo de uso en: https://.com/a/36095407/895245
La precisión máxima posible devuelta es nanosegundos, pero la precisión real está definida por la implementación y podría ser más pequeña.
Devuelve el tiempo de pared, no el uso de la CPU.
glibc 2.21 lo implementa en sysdeps/posix/timespec_get.c
y lo reenvía directamente a:
clock_gettime (CLOCK_REALTIME, ts) < 0)
clock_gettime
y CLOCK_REALTIME
son POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html , y man clock_gettime
dice que esta medida puede tener discontinuidades si cambia alguna configuración de tiempo del sistema mientras se ejecuta su programa.
C ++ 11 chrono
Ya que estamos en ello, cubrimos también: http://en.cppreference.com/w/cpp/chrono
GCC 5.3.0 (C ++ stdlib está dentro de la fuente GCC):
-
high_resolution_clock
es un alias parasystem_clock
-
system_clock
reenvía al primero de los siguientes que está disponible:-
clock_gettime(CLOCK_REALTIME, ...)
-
gettimeofday
-
time
-
-
steady_clock
avanza al primero de los siguientes que está disponible:-
clock_gettime(CLOCK_MONOTONIC, ...)
-
system_clock
-
Preguntado en: Diferencia entre std :: system_clock y std :: steady_clock?
CLOCK_REALTIME
vs CLOCK_MONOTONIC
: ¿ diferencia entre CLOCK_REALTIME y CLOCK_MONOTONIC?