2009-02-02 29 views
21

Vi en Internet que se suponía que debía usar System.nanoTime() pero eso no funciona para mí, me da el tiempo con milisegundos de precisión. Solo necesito los microsegundos antes y después de que se ejecute mi función para saber cuánto tiempo lleva. Estoy usando Windows XP.¿Cómo puedo medir el tiempo con microsegundos de precisión en Java?

Básicamente, tengo este código que, por ejemplo, hace 1 millón hasta 10 millones de inserciones en una lista vinculada a java. El problema es que no puedo medir la precisión correcta; a veces toma menos tiempo insertar todo en la lista más pequeña.

He aquí un ejemplo:

class test 
{ 
    public static void main(String args[]) 
    { 
     for(int k=1000000; k<=10000000; k+=1000000) 
     { 
      System.out.println(k); 
      LinkedList<Integer> aux = new LinkedList<Integer>(); 
      //need something here to see the start time 
      for(int i=0; i<k; i++) 
       aux.addFirst(10000); 
      //need something here to see the end time 
      //print here the difference between both times 
     } 
    } 
} 

hice esto muchas veces - hubo un bucle exterior hacerlo 20 veces para cada k - pero el resultado no son buenas. A veces toma menos tiempo hacer 10 millones de inserciones que 1 millón, porque no estoy obteniendo el tiempo correcto medido con lo que estoy usando ahora (System.nanoTime())

Edit 2: Yes, I ' m usando Sun JVM.

Editar 3: Es posible que haya hecho algo mal en el código, voy a ver si al cambiarlo hago lo que quiero.

Editar 4: Mi error, parece que System.nanoTime() funciona. Uf.

+0

¿Qué versión de Java? En mi máquina XP con JDK1.6.0_06, nanoTime() tiene precisión hasta los últimos lugares decimales. Supongo que su versión arroja valores que siempre terminan en tres ceros. – basszero

+0

Sun JVM no es suficiente, ¿qué VERSIÓN? (Su respuesta fue correcta, no hice la pregunta correcta. Supongo que todos usan Sun JVM) – basszero

+0

Java -version en el cmd me da: versión java "1.7.0-ea" Y otras 2 líneas. De cualquier manera, fue un error en mi código. Lo siento, no pude encontrar el error incluso después de un tiempo buscándolo. –

Respuesta

24

No me queda claro exactamente lo que estás evaluación comparativa, pero, en general, cualquier prueba que se lleva tales un corto período de tiempo para correr, que la precisión inferior a 50 ms es relevante, va a ser muy propenso a otras perturbaciones.

Por lo general, trato de hacer que los puntos de referencia se ejecuten durante al menos 10 segundos. El marco que estoy escribiendo en este momento adivinará cuántas iteraciones ejecutar, de modo que demorará 30 segundos. Eso significa que no obtendrá radicalmente resultados diferentes simplemente porque algún otro proceso robó la CPU durante unos pocos milisegundos.

Correr más tiempo es casi siempre un mejor enfoque que tratar de medir con precisión más fina.

3

Eso es extraño. Se supone que System.nanoTime() funciona. ¿Estás usando Sun JVM?

¿Puedes repetir tu operación 1000 veces y dividir el tiempo entre 1000 para saber lo que necesitas saber?

3

Tienes que repetir las pruebas miles de veces. Hay muchas cosas que suceden que influirán en sus medidas, como recolección de basura, E/S, intercambio de entrada/salida, el tamaño de los hilos listos para cola, etc.

30

Supongo que desde System.nanoTime() utiliza el "más preciso temporizador de sistema disponible "que aparentemente solo tiene una precisión de milisegundos en su sistema, no puede obtener nada mejor.

1

Puede ser que el sistema operativo subyacente no proporcione temporizadores con una precisión de nanosegundos.

También hay un older post.

0

Tal punto de referencia que se basa en corto intervalo de tiempo le da resultados poco confiables. Siempre obtendrá resultados diferentes, debido a factores externos como E/S, intercambio, interruptores de proceso, cachés, recolección de basura, etc.Además, la JVM optimiza sus llamadas, por lo que es probable que las primeras cosas medidas vayan más despacio que una llamada posterior. La JVM se inicia cada vez más para optimizar los comandos que ejecuta.

Además, el método como System.nanoTime() depende de los temporizadores del sistema subyacente. Pueden (y muy probablemente) no tener la granularidad para medir con esa precisión. Para citar el API:

Este método proporciona nanosegundo precisión, pero no necesariamente precisión de nanosegundos. No hay garantías en sobre la frecuencia con la que cambian los valores .

Para medir realmente con alta precisión, necesita acceder a un hardware de sincronización externo con precisión garantizada.

Para que su punto de referencia sea más estable, debe ejecutarlo más de una vez y medir intervalos de tiempo mayores que solo milisegundos.

4

System.nanoTime() utiliza un contador en la CPU y suele tener una precisión de aproximadamente 1 micro segundo en Windows XP y Linux.

Nota: Windows XP a menudo es menos preciso en máquinas multi-cpu ya que no compensa las diferentes CPU que tienen diferentes contadores. Linux lo hace. Nota 2: Se deriva con respecto al System.currentTimeMillis() ya que se basa en la precisión del reloj de su CPU (que no necesita ser tan precisa durante un período de tiempo), en lugar del reloj que usted tener para obtener el tiempo. (que se desplaza menos por día, pero tiene menos granularidad)

En su punto de referencia, básicamente está probando la velocidad a la que puede crear objetos nuevos. No sorprende que sus resultados varíen dramáticamente en función de la configuración de su GC y de la cantidad de GC que se haya realizado recientemente.

Intente ejecutar sus pruebas con las siguientes opciones y debería ver resultados muy diferentes.

-XX -verbosegc: NewSize = 128m -mx256m

2

Si quieres un resultado fiable, utilice un generador de perfiles. Sugiero VisualVM, que es fácil de instalar y se incluye con el JDK a partir de la versión 1.6.0_07. Es una herramienta visual fácil de usar que integra varias herramientas JDK de línea de comando y capacidades de generación de perfiles livianas.

1

Sí, la precisión y precisión de System.nanoTime por lo general es mucho mejor que System.currentTimeMillis, pero sin garantía: en el peor de los casos puede ser tan malo.

ThreadMXBean.getCurrentThreadCpuTime tiende a ceder tiempos menores, pero su resolución no es clara, y tiene otras desventajas (¿realmente desea el tiempo de CPU ?, la semántica dependiente de la plataforma, compatible con su plataforma?).

La medición del tiempo con las tres técnicas también tiene algún costo, es decir, requiere tiempo en sí mismo, lo que puede distorsionar las mediciones. Los costos son altamente dependientes de la plataforma, pero a menudo el costo (System.currentTimeMillis) < < costo (System.nanoTime) < < costo (ThreadMXBean.getCurrentThreadCpuTime).

Sobre la evaluación comparativa de micro en general, ver

0

una solución "rápida y sucia" que con el tiempo me fui con:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime()); 

ACTUALIZACIÓN:

originalmente Fui con System.nanoTime pero luego me di cuenta que sólo debe ser utilizado por el tiempo transcurrido, al final me ha cambiado mi código para trabajar con milisegundos o en algunos lugares de empleo:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); 

pero esto acaba de añadir ceros al final del valor (micros = millis * 1000)

izquierda esta respuesta aquí como una "señal de alerta" en caso de que otra persona piensa en nanoTime :)

0

Para nuestra reciente perfilado, me encontré con que ThreadMXBean.getCurrentThreadCpuTime() y la opción -XX: + UseLinuxPosixThreadCPUClocks hizo lo Nosotros necesitabamos.

Ver http://bugs.java.com/view_bug.do?bug_id=6888526 para más detalles

3

Usando java.time

FYI, Java 9 y posterior tiene una implementación nueva del Clock que puede capturar el momento actual en la resolución de nanosegundos.

La clase Instant representa un momento en la línea de tiempo en UTC con una resolución de nanoseconds (hasta nueve (9) dígitos de una fracción decimal).

Llame al Instant.now para capturar el momento actual.

  • En Java 9 y posterior, obtiene una resolución de hasta nanoseconds para ese momento actual.
  • En Java 8, en el momento actual es capturado sólo hasta milliseconds resolución (se puede de hecho mantener los valores de nanosegundos, pero sólo captura momento actual en milisegundos).

    Instante instantáneo = Instant.now();

representar un espacio de tiempo sin ataduras a la línea de tiempo con Duration clase. Tiene una cantidad de tiempo en términos de segundos y nanosegundos.

Duration d = Duration.between(instantThen , Instant.now()); 

Para ser claros, la resolución microseconds pedido en la pregunta se encuentra entre las granulaciones de milisegundos y nanosegundos. Número de lugares en una fracción decimal: millis es 3 (0.123), micros es 6 (0.123456), nanos es 9 (0.123456789).

Advertencia

de Java se basa en el reloj de hardware del equipo. Como otros advirtieron, ese hardware seguramente capturará el tiempo con con mucha menos precisión y que con una resolución mucho menor que nanosegundos.

Benchmarking en tal granularidad fina está plagada de problemas y no aconsejable en general.

Y tenga cuidado con premature optimization.

Hay una propuesta para agregar una instalación de micro-benchmarking a la plataforma Java en JEP 230: Microbenchmark Suite. Basado en el Java Microbenchmark Harness (JMH).


Sobre java.time

El marco java.time está incorporado en Java 8 y versiones posteriores. Estas clases suplantan a las viejas y problemáticas clases de fecha y hora legacy, como java.util.Date, Calendar, & SimpleDateFormat.

El proyecto Joda-Time, ahora en maintenance mode, recomienda la migración a las clases java.time.

Para obtener más información, consulte el Oracle Tutorial. Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310.

¿Dónde obtener las clases java.time?

  • Java SE 8 y SE 9 y más tarde
    • incorporado.
    • Parte de la API estándar de Java con una implementación integrada.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y SE 7
    • Gran parte de la funcionalidad de back-java.time está portado a Java 6 & 7 en ThreeTen-Backport.
  • Android

El proyecto se extiende ThreeTen-Extra java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time.Puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter y more.

Cuestiones relacionadas