Mida el tiempo en Linux: ¿tiempo vs reloj vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?

148

Entre las funciones de temporización, time, clock getrusage, clock_gettime, gettimeofdayy timespec_get, quiero entender con claridad cómo se aplican y cuáles son sus valores de retorno con el fin de conocer la situación en la que tengo que usarlos.

Primero debemos clasificar las funciones que devuelven valores de reloj de pared en comparación con las funciones que devuelven valores de proceso o subprocesos . gettimeofdayDevuelve el valor del reloj de pared, clock_gettimedevuelve el valor del reloj de pared o proceso o valores hilos en función del Clockparámetro pasado a ella. getrusageyclock devolver valores del proceso.

Luego, la segunda pregunta se refiere a la implementación de estas funciones y, como consecuencia, su precisión. Qué mecanismo de hardware o software utiliza estas funciones.

Parece que getrusageusa solo la marca del núcleo (generalmente 1 ms de largo) y, como consecuencia, no puede ser más precisa que el ms. ¿Es correcto? Entonces, la getimeofdayfunción parece utilizar el hardware subyacente más preciso disponible. Como consecuencia, su precisión suele ser el microsegundo (no puede ser más debido a la API) en hardware reciente. ¿Qué pasa clock, la página del manual habla de "aproximación", qué significa? ¿Qué pasa si clock_gettimela API está en nanosegundos, significa que puede ser tan precisa si el hardware subyacente lo permite? ¿Qué pasa con la monotonicidad?

¿Hay alguna otra función?

Manuel Selva
fuente

Respuestas:

198

El problema es que hay varias funciones de tiempo diferentes disponibles en C y C ++, y algunas de ellas varían en comportamiento entre implementaciones. También hay muchas medias respuestas flotando. Compilar una lista de funciones de reloj junto con sus propiedades respondería la pregunta correctamente. Para empezar, preguntemos cuáles son las propiedades relevantes que estamos buscando. Mirando tu publicación, sugiero:

  • ¿A 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 gira 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?
  • ¿La función específica es 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 usar, 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 está usando el tiempo para programar eventos o para evaluar el rendimiento. Es realmente bueno para lo que dice el 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 el tiempo del reloj de pared desde el sistema operativo, con precisión en segundos.
  • clock()parece devolver la suma del tiempo del usuario y del sistema. Está presente en C89 y posteriores. Hubo un tiempo en que se suponía que era el tiempo de CPU en ciclos, pero los estándares modernos como POSIX requieren que CLOCKS_PER_SEC sea 1000000, dando 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 alcanza el máximo (esto generalmente ocurre después de ~ 2 ^ 32 ticks, que no es muy largo para un reloj de 1 MHz). man clockdice que desde glibc 2.18 se implementa con clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...)proporciona resolución de nanosegundos, es monótono. Creo que los 'segundos' y los 'nanosegundos' se almacenan por separado, cada uno en contadores de 32 bits. Por lo tanto, cualquier ajuste ocurriría después de muchas docenas de años de tiempo de actividad. Parece un reloj muy bueno, pero desafortunadamente aún no está disponible en OS X. POSIX 7 lo describe CLOCK_MONOTONICcomo una extensión opcional .
  • getrusage()resultó ser la mejor opción para mi situación. Informa al usuario y al sistema veces 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 la hora del reloj de pared con precisión (nominalmente) µs. En mi sistema, este reloj parece tener una precisión de µs, pero esto no está garantizado, porque "la resolución del reloj del sistema depende del hardware" . POSIX.1-2008 dice eso . "Las aplicaciones deben usar la clock_gettime()función en lugar de la gettimeofday()función obsoleta ", 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 temporización de muy alta resolución (ns) en OS X. En mi sistema, esto realmente da una resolución ns. En principio, este reloj se ajusta, sin embargo, está almacenando ns usando 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 una precisión ns tanto en Linux como en OS X.

Todo lo anterior existe tanto en Linux como en OS X, salvo que se especifique lo contrario. "Mi sistema" en lo anterior es una Apple con 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 anteriores:


Actualización : para OS X, clock_gettimese implementó a partir de 10.12 (Sierra). Además, las plataformas basadas en POSIX y BSD (como OS X) comparten el rusage.ru_utimecampo de estructura.

Douglas B. Grapa
fuente
Mac OS X no tiene clock_gettime, de ahí el uso de gettimeofday()ser un poco más versátil queclock_gettime()
bobobobo
1
No ha mencionado times()(con una s), que ha existido en POSIX desde el Número 1. Con respecto a GNU / Linux: De acuerdo con la página clock()del comando man clock (3), desde glibc 2.17 y anteriores se implementó encima, pero para mejorar precisión, ahora se implementa además de clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...), que también se especifica en POSIX pero es opcional.
vinc17
2
@starflyer La precisión del reloj está parcialmente limitada por la cantidad de tiempo que lleva sondear el reloj. Esto se debe a que, si llamo al reloj y tarda 1 µs en regresar, entonces el tiempo que el reloj informa estará "apagado" en 1 µs desde la perspectiva de la persona que llama. Esto significa que un reloj de alta precisión también debe ser de baja latencia. Por lo general, uno no tendrá la compensación de la que está hablando: los relojes más baratos también serán los más precisos.
Douglas B. Staple
3
Además, la mayoría de los relojes no se preocupan por el horario de verano / zonas horarias, incluso si se consideran relojes de pared . Ambos timey gettimeofdaydevuelven, al menos hoy en día, segundos desde época (también conocido como unix-timestamps). Esto es independiente de las zonas horarias / DST. Los segundos bisiestos son otra historia ...
Zulan
2
Para los usuarios de Android, usar CLOCK_MONOTONIC puede ser problemático ya que la aplicación puede suspenderse, junto con el reloj. Para eso, Android agregó el temporizador ANDROID_ALARM_ELAPSED_REALTIME al que se puede acceder a través de ioctl. Aquí
Itay Bianco
17

C11 timespec_get

Ejemplo de uso en: https://stackoverflow.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 menor.

Devuelve el tiempo de la pared, no el uso de la CPU.

glibc 2.21 lo implementa debajo sysdeps/posix/timespec_get.cy lo reenvía directamente a:

clock_gettime (CLOCK_REALTIME, ts) < 0)

clock_gettimey CLOCK_REALTIMEson POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html , y man clock_gettimedice que esta medida puede tener discontinuidades si cambia alguna configuración de la hora del sistema mientras se ejecuta el programa.

C ++ 11 crono

Ya que estamos en eso, vamos a cubrirlos también: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (C ++ stdlib está dentro de la fuente de GCC):

  • high_resolution_clock es un alias para system_clock
  • system_clock reenvía a la primera de las siguientes opciones disponibles:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock reenvía a la primera de las siguientes opciones disponibles:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Preguntado por: ¿ Diferencia entre std :: system_clock y std :: steady_clock?

CLOCK_REALTIMEvs CLOCK_MONOTONIC: Diferencia entre CLOCK_REALTIME y CLOCK_MONOTONIC?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Gran respuesta que desmitifica las implementaciones típicas. Eso es lo que la gente realmente necesita saber.
Celess