variable manejo localdatetime horas ejemplo current java windows datetime time

manejo - time java ejemplo



¿Por qué System.nanoTime() y System.currentTimeMillis() se separan tan rápidamente? (5)

Para fines de diagnóstico, quiero poder detectar cambios en el reloj de la hora del día del sistema en una aplicación de servidor de larga ejecución. Como System.currentTimeMillis() se basa en la hora del reloj de pared y System.nanoTime() se basa en un temporizador del sistema que es independiente (*) de la hora del reloj de pared, pensé que podría usar cambios en la diferencia entre estos valores para detectar el sistema Cambios de tiempo.

Escribí una aplicación de prueba rápida para ver cuán estable es la diferencia entre estos valores, y para mi sorpresa, los valores divergen inmediatamente para mí en el nivel de varios milisegundos por segundo. Algunas veces vi divergencias mucho más rápidas. Esto está en un escritorio Win7 de 64 bits con Java 6. No he probado este programa de prueba a continuación en Linux (o Solaris o MacOS) para ver cómo funciona. Para algunas ejecuciones de esta aplicación, la divergencia es positiva, para algunas ejecuciones es negativa. Parece depender de lo que está haciendo el escritorio, pero es difícil de decir.

public class TimeTest { private static final int ONE_MILLION = 1000000; private static final int HALF_MILLION = 499999; public static void main(String[] args) { long start = System.nanoTime(); long base = System.currentTimeMillis() - (start / ONE_MILLION); while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Don''t care if we''re interrupted } long now = System.nanoTime(); long drift = System.currentTimeMillis() - (now / ONE_MILLION) - base; long interval = (now - start + HALF_MILLION) / ONE_MILLION; System.out.println("Clock drift " + drift + " ms after " + interval + " ms = " + (drift * 1000 / interval) + " ms/s"); } } }

Las inexactitudes con el tiempo Thread.sleep() , así como las interrupciones, deben ser totalmente irrelevantes para la deriva del temporizador.

Estas dos llamadas al "Sistema" de Java están diseñadas para usarse como una medida: una para medir las diferencias en el tiempo del reloj de pared y la otra para medir intervalos absolutos, por lo que cuando no se cambia el tiempo real, estos valores deben cambiar a muy cerca de la misma velocidad, ¿verdad? ¿Es esto un error o una debilidad o un error en Java? ¿Hay algo en el sistema operativo o hardware que impida que Java sea más preciso?

Espero totalmente alguna desviación y fluctuación (**) entre estas mediciones independientes, pero esperaba menos de un minuto por día de desviación. 1 ms por segundo de deriva, si es monotónico, ¡es casi 90 segundos! Mi deriva en el peor de los casos fue tal vez diez veces más. Cada vez que ejecuto este programa, veo la deriva en la primera medición. Hasta ahora, no he ejecutado el programa durante más de unos 30 minutos.

Espero ver una pequeña aleatoriedad en los valores impresos, debido a la inestabilidad, pero en casi todas las ejecuciones del programa veo un aumento constante de la diferencia, a menudo hasta 3 ms por segundo de aumento y un par de veces más que eso .

¿Alguna versión de Windows tiene un mecanismo similar al de Linux que ajusta la velocidad del reloj del sistema para que el reloj de la hora del día se sincronice con la fuente del reloj externo? ¿Influiría tal cosa en ambos temporizadores, o solo en el reloj de pared?

(*) Entiendo que en algunas arquitecturas, System.nanoTime() usará necesariamente el mismo mecanismo que System.currentTimeMillis() . También creo que es justo asumir que cualquier servidor moderno de Windows no es una arquitectura de hardware. ¿Es esta una mala suposición?

(**) Por supuesto, System.currentTimeMillis() normalmente tendrá una fluctuación mucho mayor que System.nanoTime() ya que su granularidad no es de 1 ms en la mayoría de los sistemas.


¿Alguna versión de Windows tiene un mecanismo similar al de Linux que ajusta la velocidad del reloj del sistema para que el reloj de la hora del día se sincronice con la fuente del reloj externo? ¿Influiría tal cosa en ambos temporizadores, o solo en el reloj de pared?

El Proyecto de marca de tiempo de Windows hace lo que estás pidiendo. Por lo que sé, solo afecta al temporizador del reloj de pared.


"Devuelve el valor actual del temporizador de sistema disponible más preciso, en nanosegundos.

"Este método solo puede usarse para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o tiempo de reloj de pared. El valor devuelto representa nanosegundos ya que es un tiempo fijo pero arbitrario (quizás en el futuro, por lo que los valores pueden ser negativos) Este método proporciona una precisión de nanosegundos, pero no necesariamente una precisión de nanosegundos. No se garantiza la frecuencia con la que cambian los valores. Las diferencias en las llamadas sucesivas que abarcan más de aproximadamente 292 años (2 ** 63 nanosegundos) no calcularán con precisión el tiempo transcurrido debido a números rebosar."

Tenga en cuenta que dice "precisa", no "precisa".

No es un "error en Java" o un "error" en nada. Es una definicion Los desarrolladores de JVM miran a su alrededor para encontrar el reloj / temporizador más rápido en el sistema y usarlo. Si eso está en bloqueo con el reloj del sistema, entonces está bien, pero si no lo está, así es como la cookie se desmorona. Es totalmente plausible, digamos, que un sistema informático tendrá un reloj de sistema preciso pero luego tendrá un temporizador de mayor velocidad interno que esté vinculado a la velocidad de reloj de la CPU o algo así. Dado que la frecuencia de reloj varía con frecuencia para minimizar el consumo de energía, la tasa de incremento de este temporizador interno variaría.


Es posible que este post de Sun / Oracle sobre los temporizadores de JVM sea ​​de su interés.

Aquí hay un par de párrafos de ese artículo acerca de los temporizadores JVM en Windows:

System.currentTimeMillis() se implementa mediante el método GetSystemTimeAsFileTime , que esencialmente solo lee el valor de baja resolución de la hora del día que Windows mantiene. La lectura de esta variable global es naturalmente muy rápida: alrededor de 6 ciclos según la información reportada. Este valor de la hora del día se actualiza a una velocidad constante, independientemente de cómo se haya programado la interrupción del temporizador. Dependiendo de la plataforma, será 10ms o 15ms (este valor parece estar vinculado al período de interrupción predeterminado).

System.nanoTime() se implementa utilizando la API QueryPerformanceCounter / QueryPerformanceFrequency (si está disponible, de lo contrario, devuelve currentTimeMillis*10^6 ). QueryPerformanceCounter (QPC) se implementa de diferentes maneras dependiendo del hardware en el que se está ejecutando. Por lo general, utilizará el temporizador de intervalo programable (PIT), el temporizador de administración de energía ACPI (PMT) o el contador de marca de tiempo (TSC) a nivel de la CPU. El acceso al PIT / PMT requiere la ejecución de instrucciones lentas del puerto de E / S y, como resultado, el tiempo de ejecución para QPC es del orden de microsegundos. En contraste, la lectura del TSC es del orden de 100 ciclos de reloj (para leer el TSC del chip y convertirlo en un valor de tiempo basado en la frecuencia de operación). Puede saber si su sistema usa el PMT de ACPI al verificar si QueryPerformanceFrequency devuelve el valor de firma de 3,579,545 (es decir, 3.57MHz). Si ve un valor de alrededor de 1.19Mhz, entonces su sistema está utilizando el antiguo chip PIT 8245. De lo contrario, debería ver un valor aproximado al de la frecuencia de su CPU (modulo a cualquier velocidad o administración de energía que pueda estar vigente).


No estoy seguro de cuánto ayudará esto realmente. Pero esta es un área de cambio activo en el mundo Windows / Intel / AMD / Java. La necesidad de una medición precisa y precisa del tiempo ha sido evidente durante varios (al menos 10) años. Tanto Intel como AMD han respondido cambiando el funcionamiento de TSC. Ambas compañías ahora tienen algo llamado Invariant-TSC y / o Constant-TSC .

Compruebe la precisión rdtsc en los núcleos de la CPU . Cita de osgx (que hace referencia a un manual de Intel).

"16.11.1 TSC invariante

El contador de marca de tiempo en los procesadores más nuevos puede admitir una mejora, denominada TSC invariante. El soporte del procesador para invariantes TSC se indica mediante PUID.80000007H: EDX [8].

El invariante TSC se ejecutará a una velocidad constante en todos los ACPI P-, C-. y estados T Este es el comportamiento arquitectónico que avanza. En los procesadores con compatibilidad invariable con TSC, el sistema operativo puede usar el TSC para los servicios de temporizador de reloj de pared (en lugar de los temporizadores ACPI o HPET). Las lecturas de TSC son mucho más eficientes y no incurren en la sobrecarga asociada con una transición de anillo o el acceso a un recurso de plataforma ".

Consulte también http://www.citihub.com/requesting-timestamp-in-applications/ . Cita del autor

Para AMD:

Si CPUID 8000_0007.edx [8] = 1, se garantiza que la tasa de TSC es invariante en todos los estados P, estados C y transiciones stop-grant (como STPCLK Throttling); por lo tanto, el TSC es adecuado para su uso como una fuente de tiempo.

Para Intel:

La compatibilidad del procesador con el invariante TSC se indica mediante CPUID.80000007H: EDX [8]. El invariante TSC se ejecutará a una velocidad constante en todos los ACPI P-, C-. y estados T Este es el comportamiento arquitectónico que avanza. En los procesadores con compatibilidad invariable con TSC, el sistema operativo puede usar el TSC para los servicios de temporizador de reloj de pared (en lugar de los temporizadores ACPI o HPET). Las lecturas de TSC son mucho más eficientes y no incurren en la sobrecarga asociada con una transición de anillo o el acceso a un recurso de plataforma ".

Ahora, el punto realmente importante es que las últimas JVM parecen explotar los mecanismos de TSC recientemente confiables. No hay mucho en línea para mostrar esto. Sin embargo, eche un vistazo a http://code.google.com/p/disruptor/wiki/PerformanceResults .

"Para medir la latencia tomamos la tubería de tres etapas y generamos eventos a menos de la saturación. Esto se logra esperando 1 microsegundo después de inyectar un evento antes de inyectar el siguiente y repetir 50 millones de veces. Para medir el tiempo en este nivel de precisión es necesario usamos contadores de marca de tiempo de la CPU. Elegimos CPU con un TSC invariante porque los procesadores más antiguos sufren cambios de frecuencia debido al ahorro de energía y los estados de suspensión. Los procesadores Intel Nehalem y posteriores utilizan un TSC invariante al que pueden acceder las últimas JVM de Oracle que se ejecutan en Ubuntu 11.04. No se ha empleado ningún enlace de CPU para esta prueba "

Tenga en cuenta que los autores del "Disruptor" tienen vínculos estrechos con las personas que trabajan en el Azul y otras JVM.

Véase también "Registros de vuelo de Java detrás de las escenas". Esta presentación menciona las nuevas instrucciones invariantes de TSC.


System.currentTimeMillis() y System.nanoTime() no son necesariamente proporcionados por el mismo hardware. System.currentTimeMillis() , respaldado por GetSystemTimeAsFileTime() tiene elementos de resolución de 100 ns. Su fuente es el temporizador del sistema. System.nanoTime() está respaldado por el contador de alto rendimiento del sistema. Existe una gran variedad de hardware diferente que proporciona este contador. Por lo tanto su resolución varía, dependiendo del hardware subyacente.

En ningún caso se puede suponer que estas dos fuentes están en fase. La medición de los dos valores entre sí revelará una velocidad de carrera diferente. Si la actualización de System.currentTimeMillis() se toma como el progreso real en el tiempo, la salida de System.nanoTime() puede ser a veces más lenta, a veces más rápida y también variable.

Se debe realizar una calibración cuidadosa para bloquear las fases de estas dos fuentes de tiempo.

Una descripción más detallada de la relación entre estas dos fuentes de tiempo se puede encontrar en el Proyecto de marca de tiempo de Windows .