¿Diferencia entre CLOCK_REALTIME y CLOCK_MONOTONIC?


206

¿Podría explicar la diferencia entre CLOCK_REALTIMEy los CLOCK_MONOTONICrelojes devueltos por clock_gettime()Linux?

¿Cuál es una mejor opción si necesito calcular el tiempo transcurrido entre las marcas de tiempo producidas por una fuente externa y la hora actual?

Por último, si tengo un demonio NTP que ajusta periódicamente la hora del sistema, ¿cómo interactúan estos ajustes con cada uno de CLOCK_REALTIMEy CLOCK_MONOTONIC?

Respuestas:


238

CLOCK_REALTIMErepresenta la mejor estimación de la máquina en cuanto al reloj de pared actual, la hora del día. Como dicen Ignacio y MarkR , esto significa que CLOCK_REALTIMEpuede saltar hacia adelante y hacia atrás a medida que cambia el reloj de la hora del día del sistema, incluido el NTP.

CLOCK_MONOTONICrepresenta el tiempo absoluto transcurrido del reloj de pared desde un punto fijo arbitrario en el pasado. No se ve afectado por los cambios en el reloj de la hora del día del sistema.

Si desea calcular el tiempo transcurrido entre dos eventos observados en una máquina sin un reinicio intermedio, CLOCK_MONOTONICes la mejor opción.

Tenga en cuenta que en Linux, CLOCK_MONOTONICno mide el tiempo dedicado a la suspensión, aunque según la definición POSIX debería hacerlo. Puede usar el específico CLOCK_BOOTTIMEde Linux para un reloj monótono que se sigue ejecutando durante la suspensión.


11
Tenga en cuenta que en los núcleos más nuevos, CLOCK_MONOTONIC_RAW está disponible, lo cual es aún mejor (sin ajustes de NTP).
Joseph Garvin

14
@JosephGarvin por algún valor de "mejor", tal vez - CLOCK_MONOTONIC_RAW puede correr rápido o lento en tiempo real en varias (o varios cientos) partes por millón, y su tasa puede variar debido a condiciones ambientales como temperatura o voltaje (o tiempo de robo en maquinas virtuales). En una máquina que funciona correctamente, NTP hace todo lo posible para mitigar todos esos factores y, por lo tanto, CLOCK_MONOTONIC refleja más de cerca el tiempo transcurrido verdadero .
hobbs

23
De acuerdo, podría ser interesante tener un CLOCK_MONOTONIC_PARBOILED que se vio afectado por los esfuerzos de NTP para corregir errores de frecuencia, pero que no se vio afectado por sus esfuerzos para corregir errores de fase, pero eso es mucha complejidad para una ganancia dudosa :)
hobbs

1
Me gusta el punto que menciona @hobbs. ¿Qué sucede si le preocupan los programas que pueden verse afectados por la deriva del reloj? ¿ CLOCK_MONOTONICSería la mejor opción en ese escenario? por ejemplo, sistema de misiles Patriot
sjagr

3
Creo que también es importante mencionar que CLOCK_REALTIME se ve afectado por los segundos bisiestos. Esto significa que se va a producir el doble marcas de tiempo cada vez que se inserta un segundo salto. La última vez que esto sucedió el 30 de junio de 2012 y bastante software tuvo problemas .
user1202136

38

El libro de Robert Love, LINUX System Programming 2nd Edition , aborda específicamente su pregunta al comienzo del Capítulo 11, página 363:

El aspecto importante de una fuente de tiempo monótono NO es el valor actual, sino la garantía de que la fuente de tiempo aumenta estrictamente linealmente y, por lo tanto, es útil para calcular la diferencia de tiempo entre dos muestreos.

Dicho esto, creo que está asumiendo que los procesos se ejecutan en la misma instancia de un sistema operativo, por lo que es posible que desee realizar una calibración periódica para poder estimar la deriva.


25

CLOCK_REALTIME se ve afectado por NTP y puede moverse hacia adelante y hacia atrás. CLOCK_MONOTONICno lo es, y avanza a una marca por marca.


15
CLOCK_MONOTONIC se ve afectado por el ajuste de hora de NTP (tiempo de rotación). Sin embargo, no saltará.
derobert

3
Pero en los núcleos más nuevos hay CLOCK_MONOTONIC_RAW, que realmente no se ve afectado por NTP.
Joseph Garvin

1
"tick": ¿alguna idea aproximada de cuán grande / larga / instrucciones de CPU es un tick en Linux / amd64? ¿O dónde puedo obtener documentos sobre esto?
kevinarpe

@kevinarpe No estoy seguro, pero creo que un tic se define como una fracción de tiempo, no un número de ciclos de CPU, a menudo es 1/100 de segundo.
Stéphane

@ Stéphane: Seguramente debo tener más de 10 ms. Creo que Java System.nanoTime()usa CLOCK_MONOTONICy puede medir duraciones de 1000ns o menos. ¿Quizás está pensando en la hora del sistema, que a veces se limita a milisegundos?
kevinarpe

20

Además de la respuesta de Ignacio , CLOCK_REALTIMEpuede avanzar hacia adelante a pasos agigantados y, ocasionalmente, hacia atrás. CLOCK_MONOTONICtampoco lo hace; simplemente sigue avanzando (aunque probablemente se restablece al reiniciar).

Una aplicación robusta debe ser capaz de tolerar CLOCK_REALTIMEsaltos hacia adelante ocasionalmente (y quizás hacia atrás muy levemente muy ocasionalmente, aunque eso es más un caso marginal).

Imagine lo que sucede cuando suspende su computadora portátil: CLOCK_REALTIMEsalta hacia adelante después del currículum, CLOCK_MONOTONICno lo hace. Pruébalo en una máquina virtual.


3
CLOCK_MONOTONIC comienza en 0 cuando se inicia el programa; No es para uso entre procesos.
Benubird

18
@Benubird: no comienza en 0 cuando se inicia el programa. Eso es CLOCK_PROCESS_CPUTIME_ID. Prueba rápida: $ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279. Ese número coincide con el tiempo de actividad del sistema en Linux, pero el estándar dice que es arbitrario.
derobert

44
Por otro lado, no creo que el comportamiento de Linux donde se CLOCK_MONOTONICdetiene durante una suspensión / reanudación sea conforme con POSIX. Se supone que es el tiempo desde un punto fijo en el pasado, pero detener el reloj por suspender / reanudar rompe eso.
caf

15

POSIX 7 citas

POSIX 7 especifica ambos en http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html :

CLOCK_REALTIME:

Este reloj representa el reloj que mide el tiempo real del sistema. Para este reloj, los valores devueltos por clock_gettime () y especificados por clock_settime () representan la cantidad de tiempo (en segundos y nanosegundos) desde la época.

CLOCK_MONOTONIC (característica opcional):

Para este reloj, el valor devuelto por clock_gettime () representa la cantidad de tiempo (en segundos y nanosegundos) desde un punto no especificado en el pasado (por ejemplo, el tiempo de inicio del sistema o la Época). Este punto no cambia después del tiempo de inicio del sistema. El valor del reloj CLOCK_MONOTONIC no se puede establecer a través de clock_settime ().

clock_settime() da una pista importante: los sistemas POSIX pueden cambiar arbitrariamente CLOCK_REALITME con él, así que no confíes en que fluya de manera continua ni hacia adelante. NTP podría implementarse usando clock_settime(), y solo podría afectar CLOCK_REALITME.

La implementación del kernel de Linux parece tomar tiempo de arranque como la época para CLOCK_MONOTONIC: Punto de partida para CLOCK_MONOTONIC


0

Lo sentimos, no hay reputación para agregar esto como un comentario. Entonces va como una respuesta complementaria.

Dependiendo de la frecuencia con la que llame clock_gettime(), debe tener en cuenta que solo algunos de los "relojes" son proporcionados por Linux en el VDSO (es decir, no requieren una llamada al sistema con todos los gastos generales de uno), que solo empeoró cuando se agregó Linux las defensas para proteger contra ataques similares a Spectre).

Si bien clock_gettime(CLOCK_MONOTONIC,...), clock_gettime(CLOCK_REALTIME,...)y gettimeofday()siempre serán extremadamente rápidos (acelerados por el VDSO), esto no es cierto para, por ejemplo, CLOCK_MONOTONIC_RAW o cualquiera de los otros relojes POSIX.

Esto puede cambiar con la versión del kernel y la arquitectura.

Aunque la mayoría de los programas no necesitan prestar atención a esto, puede haber picos de latencia en los relojes acelerados por el VDSO: si los golpea justo cuando el núcleo está actualizando el área de memoria compartida con los contadores de reloj, tiene que esperar a que grano para terminar.

Aquí está la "prueba" (GitHub, para mantener a los bots alejados de kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7


0

CLOCK_REALTIME : Tiempo absoluto (p. Ej. 01/07/2020)

CLOCK_MONOTONIC: Tiempo relativo (p. Ej., 5 segundos a partir de ahora o hace 10 minutos)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.