2009-09-30 11 views
14

Java da acceso a dos métodos para obtener la hora actual: System.nanoTime() y System.currentTimeMillis(). El primero da un resultado en nanosegundos, pero la precisión real es mucho peor que eso (muchos microsegundos).Medición de tiempo precisa en Java

¿La JVM ya ofrece el mejor valor posible para cada máquina en particular? De lo contrario, ¿hay alguna biblioteca de Java que pueda proporcionar una medición más precisa, posiblemente al estar vinculada a un sistema en particular?

+0

¿En qué sistema operativo demostraste que System.nanoTime() producía una salida que estaba desactivada por "muchos microsegundos"? –

+0

Estaba en un sistema Linux en una máquina de doble núcleo, pero era una instalación bastante antigua (desde principios de 2007 ...). Tal vez esa fue la causa. Volveré a revisar algo más reciente. También por lo que recuerdo, tuve llamadas sucesivas que devolvían el mismo valor y saltaban unos pocos microrsegundos. – penpen

Respuesta

13

El problema para obtener mediciones de tiempo súper precisas es que algunos procesadores no pueden/no proporcionan incrementos tan pequeños.

Hasta donde yo sé, System.currentTimeMillis() y System.nanoTime() es la mejor medida que podrá encontrar.

Tenga en cuenta que ambos devuelven un valor de long.

+0

Los procesadores modernos (> 1ghz) ciclo más rápido que 1 nanosegundo, por lo que son técnicamente muy capaces. –

+2

Podrían hacer un seguimiento de la hora, pero eso no significa que estén informando el tiempo con precisión. – jjnguy

+2

No olvide que hay sobrecarga: Hay una llamada al sistema implicada que típicamente es del orden de microsegundos en sí (solo para saltar al kernel y volver atrás, pero esa es la parte costosa para una lectura de reloj). Luego puede tener un sistema cargado con prioridad habilitada, lo que significa que se puede programar otro proceso. Incluso si este no es el caso, eso significa que todavía tiene que saltar a la JVM e incluso con el código JIT va a haber una ligera sobrecarga. En gode nativo, puede usar la API clock_gettime & friends para explorar la precisión de los temporizadores de alta resolución. – Vitali

1

Desafortunadamente, no creo que Java RTS sea lo suficientemente maduro en este momento.

El tiempo de Java intenta proporcionar el mejor valor (en realidad, delegan el código nativo para llamar para obtener la hora de kernal). Sin embargo, las especificaciones de JVM hacen que este descargo de responsabilidad general de medición de tiempo se use principalmente para cosas como las actividades de GC y soporte del sistema subyacente.

  • Ciertas actividades de GC bloquearán todos los hilos, incluso si está ejecutando simultáneamente GC.
  • la precisión predeterminada de la marca del reloj de Linux es de solo 10ms. Java no puede mejorarlo si linux kernal no es compatible.

No he descubierto cómo abordar el # 1 a menos que tu aplicación no necesite hacer GC. Una aplicación decente y de tamaño mediano probablemente y ocasionalmente se gaste como decenas de milisegundos en las pausas de GC. Probablemente no tenga suerte si su requisito de precisión es inferior a 10 ms.

En cuanto al n. ° 2, puede tune the linux kernal para dar más precisión. Sin embargo, también obtiene menos de su caja porque ahora el contexto kernal cambia más a menudo.

Tal vez, deberíamos verlo en un ángulo diferente. ¿Hay alguna razón por la cual OPS necesita una precisión de 10 ms por debajo? ¿Está bien decirle a Ops que la precisión es de 10ms Y también mirar el registro del GC en ese momento, para que sepan que el tiempo es + -10ms preciso sin actividad de GC en ese momento?

+0

"Ciertas actividades de GC bloquearán todos los hilos incluso si están ejecutando GC concurrente ". Tiene razón, pero, por otro lado, con algunos ajustes de los parámetros de JVM, esto se puede aliviar parcialmente. Y según lo propuesto, sí, el tiempo transcurrido en GC se puede tener en cuenta y eliminar. – penpen

+0

Mi punto no es que no podamos ajustarlo. Mi punto es que no puedes hacer que el GC baje al nivel de nanosegundos que pareces querer, incluso si lo sintonizas. Esa fue mi definición de aplicaciones "decentes", que ya deberían estar sintonizadas :) –

5

No tiene sentido en Java medir el tiempo hasta la escala de nanosegundos; un golpe ocasional de GC eliminará fácilmente cualquier tipo de precisión que esto pueda haber proporcionado. En cualquier caso, la documentación indica que, si bien proporciona una precisión de nanosegundos, no es lo mismo que una precisión de nanosegundos; y hay sistemas operativos que no informan nanosegundos en ningún caso (razón por la cual encontrará respuestas cuantificadas a 1000 al acceder a ellas, no es suerte, es una limitación).

No solo eso, sino que dependiendo de cómo el sistema operativo realmente implemente la función, es posible que encuentre resultados cuantificados de todos modos (por ejemplo, respuestas que siempre terminan en 64 o 128 en lugar de valores intermedios).

También vale la pena señalar que el propósito del método es encontrar las dos diferencias de tiempo entre alguna hora de inicio (cercana) y ahora; si toma System.nanoTime() al inicio de una aplicación de larga ejecución y luego toma System.nanoTime() mucho tiempo después, es posible que se haya desviado bastante del tiempo real.Entonces solo deberías usarlo por períodos de menos de 1s; si necesita un tiempo de ejecución más largo que eso, milisegundos deberían ser suficientes. (Y si no es así, invente los últimos números, probablemente impresionará a los clientes y el resultado será igual de válido.)

+0

"Así que solo deberías usarlo realmente por períodos de menos de 1s". Es para pequeños fenómenos repetidos. "Y si no es así, invente los últimos números". Nah, es posible que quieran tratar de reproducir esto :) – penpen

0

Si está buscando registrar algún tipo de fenómeno en el orden de nanosegundos, lo que realmente necesitas es un real-time operating system. La precisión del temporizador dependerá en gran medida de la implementación del sistema operativo de su high resolution timer y del hardware subyacente.

Sin embargo, todavía puede permanecer con Java ya que hay versiones de RTOS disponibles.

0

JNI: Crea una función simple para acceder a la instrucción Intel RDTSC o al registro PMCCNTR del coprocesador p15 en ARM.

Pure Java: Posiblemente pueda obtener mejores valores si está dispuesto a retrasar hasta que el reloj marque. Puede girar comprobando System.nanoTime() hasta que el valor cambie. Si sabe, por ejemplo, que el valor de System.nanoTime() cambia cada 10000 iteraciones de bucle en su plataforma por la cantidad DELTA, entonces el tiempo real del evento fue finalNanoTime-DELTA * ITERATIONS/10000. Deberá "calentar" el código antes de tomar medidas reales.

Hack (para perfiles, etc., solamente): Si la recolección de basura que está lanzando fuera siempre se puede medir el tiempo de uso de un hilo de alta prioridad que se ejecuta en un segundo JVM que no crea objetos. Hazlo girar incrementando un largo en la memoria compartida que utilizas como reloj.

Cuestiones relacionadas