Pregunta

¿Cómo se escribe (y ejecutar) una correcta micro-punto de referencia en Java?

Estoy buscando algunos ejemplos de código y los comentarios que ilustran varias cosas en las que pensar.

Ejemplo:Si el punto de referencia de medida del tiempo/iteración o iteraciones/tiempo, y por qué?

Relacionado con: Es cronómetro benchmarking aceptable?

¿Fue útil?

Solución

Consejos sobre la escritura de micro puntos de referencia de los creadores de Java HotSpot:

Regla 0: Leer una buena reputación de papel en la Jvm y micro-benchmarking.Un buen ejemplo es Brian Goetz, 2005.No esperar demasiado de los micro-puntos de referencia;miden sólo una gama limitada de JVM características de rendimiento.

Regla 1: Incluir siempre un calentamiento de la fase en la que se ejecuta el test núcleo de todo el camino a través de, lo suficiente como para activar todas las inicializaciones y compilaciones antes de tiempo de la fase(s).(Menor número de iteraciones es ACEPTAR en la fase de calentamiento.La regla de oro es de varias decenas de miles de personas del interior del bucle de iteraciones.)

Regla 2: Siempre se ejecutan con -XX:+PrintCompilation, -verbose:gc, etc., así que usted puede comprobar que el compilador y otras partes de la JVM no están haciendo lo inesperado de trabajo durante su tiempo de fase.

La regla 2.1: Los mensajes de impresión al inicio y al final de la temporización y fases de calentamiento, para que pueda comprobar que no hay ningún resultado de la Regla 2 durante la fase de temporización.

Regla 3: Ser consciente de la diferencia entre -client y -server, y OSR y regular las compilaciones.El -XX:+PrintCompilation indicador informes de OSR compilaciones con un signo para indicar la no-punto de entrada inicial, por ejemplo: Trouble$1::run @ 2 (41 bytes).Prefieren el servidor al cliente, y la regular a OSR, si usted está después de un mejor rendimiento.

Regla 4: Ser consciente de inicialización de efectos.No se imprimen por primera vez durante la duración de la fase, ya que la impresión de carga e inicializa las clases.No cargue nuevas clases fuera de la fase de calentamiento (o final de la fase de información), a menos que las pruebas de carga de clases específicamente (y en ese caso, la carga sólo las clases de prueba).Regla 2 es tu primera línea de defensa contra tales efectos.

Regla 5: Ser consciente de deoptimization y recompilación efectos.No tome ninguna ruta de acceso del código por primera vez en el calendario de la fase, ya que el compilador no deseado y volver a compilar el código, basado en una anterior optimista de la suposición de que el camino no iba a ser utilizado en su totalidad.Regla 2 es tu primera línea de defensa contra tales efectos.

Regla 6: El uso apropiado de herramientas para leer el compilador de la mente, y esperar a ser sorprendido por el código que produce.Inspeccionar el código antes de la formación de teorías acerca de lo que hace algo más rápido o más lento.

Regla 7: Reducir el ruido en las mediciones.Ejecutar su punto de referencia en una zona tranquila de la máquina, y ejecutarlo varias veces, descartando los valores atípicos.Uso -Xbatch para serializar el compilador con la aplicación, y considere la posibilidad de establecer -XX:CICompilerCount=1 para evitar que el compilador ejecuta en paralelo con la misma.Intente su mejor para reducir la GC gastos generales, establecer Xmx(suficientemente grande) es igual a Xms y el uso de UseEpsilonGC si está disponible.

Regla 8: El uso de una biblioteca para su referencia es probablemente más eficiente y ya estaba depurando para este único propósito.Como JMH, Pinza o Bill y Paul Excelente UCSD puntos de referencia para Java.

Otros consejos

Las cosas importantes para los puntos de referencia de Java son:

  • Primero calienta el JIT ejecutando el código varias veces antes de sincronizarlo
  • Asegúrese de ejecutarlo el tiempo suficiente para poder medir los resultados en segundos o (mejor) decenas de segundos
  • Si bien no puede llamar a System.gc() entre iteraciones, es una buena idea ejecutarlo entre pruebas, para que cada prueba obtenga un " clean " espacio de memoria para trabajar. (Sí, gc() es más una pista que una garantía, pero es muy probable que realmente acumule basura en mi experiencia).
  • Me gusta mostrar las iteraciones y el tiempo, y una puntuación de tiempo / iteración que se puede escalar de modo que el & "; mejor &"; El algoritmo obtiene una puntuación de 1.0 y otros se puntúan de manera relativa. Esto significa que puede ejecutar los algoritmos all durante mucho tiempo, variando tanto el número de iteraciones como el tiempo, pero aún obteniendo resultados comparables.

Estoy en el proceso de bloguear sobre el diseño de un marco de referencia en .NET. Tengo una pareja de anterior publicaciones que pueden darle algunas ideas; no todo será apropiado, por supuesto, pero algunas pueden serlo.

jmh es una adición reciente a OpenJDK y ha sido escrito por Algunos ingenieros de rendimiento de Oracle. Sin duda vale la pena echarle un vistazo.

  

El jmh es un arnés de Java para construir, ejecutar y analizar puntos de referencia nano / micro / macro escritos en Java y otros lenguajes destinados a la JVM.

Información muy interesante enterrada en los comentarios de las pruebas de muestra .

Ver también:

  

¿Debe el punto de referencia medir tiempo / iteración o iteraciones / tiempo, y por qué?

Depende de qué está intentando probar.

Si está interesado en latencia , use tiempo / iteración y si está interesado en rendimiento , use iteraciones / tiempo.

Asegúrese de utilizar de alguna manera los resultados que se calculan en código de referencia. De lo contrario, su código se puede optimizar.

Si está tratando de comparar dos algoritmos, haga al menos dos puntos de referencia para cada uno, alternando el orden. es decir:

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

He encontrado algunas diferencias notables (5-10% a veces) en el tiempo de ejecución del mismo algoritmo en diferentes pases ...

Además, asegúrese de que n sea muy grande, de modo que el tiempo de ejecución de cada ciclo sea de al menos 10 segundos más o menos. Cuantas más iteraciones, cifras más significativas en su tiempo de referencia y más confiables sean los datos.

Hay muchas posibles dificultades para escribir micro-puntos de referencia en Java.

Primero: debe calcular con todo tipo de eventos que toman tiempo más o menos al azar: recolección de basura, efectos de almacenamiento en caché (del sistema operativo para archivos y de la CPU para memoria), IO, etc.

Segundo: no puede confiar en la precisión de los tiempos medidos durante intervalos muy cortos.

Tercero: la JVM optimiza su código mientras se ejecuta. Por lo tanto, diferentes ejecuciones en la misma instancia de JVM serán cada vez más rápidas.

Mis recomendaciones: haga que su punto de referencia se ejecute unos segundos, eso es más confiable que un tiempo de ejecución durante milisegundos. Calentar la JVM (significa ejecutar el punto de referencia al menos una vez sin medir, para que la JVM pueda ejecutar optimizaciones). Y ejecute su punto de referencia varias veces (tal vez 5 veces) y tome el valor medio. Ejecute cada micro-punto de referencia en una nueva instancia de JVM (llame a cada nuevo punto de referencia Java), de lo contrario, los efectos de optimización de la JVM pueden influir en las pruebas posteriores. No ejecute cosas que no se ejecutan en la fase de calentamiento (ya que esto podría desencadenar carga de clase y recompilación).

También se debe tener en cuenta que también podría ser importante analizar los resultados del micro punto de referencia al comparar diferentes implementaciones. Por lo tanto, se debe realizar una prueba de significación .

Esto se debe a que la implementación A podría ser más rápida durante la mayoría de las ejecuciones del punto de referencia que la implementación B. Pero <=> también podría tener una mayor difusión, por lo que el beneficio de rendimiento medido de <=> no será de ninguna importancia en comparación con <=>.

Entonces, también es importante escribir y ejecutar un micro benchmark correctamente, pero también analizarlo correctamente.

http://opt.sourceforge.net/ Java Micro Benchmark: tareas de control necesarias para determinar la comparación Características de rendimiento del sistema informático en diferentes plataformas. Se puede utilizar para guiar las decisiones de optimización y comparar diferentes implementaciones de Java.

Para agregar al otro excelente consejo, también sería consciente de lo siguiente:

Para algunas CPU (por ejemplo, la gama Intel Core i5 con TurboBoost), la temperatura (y la cantidad de núcleos que se utilizan actualmente, así como su porcentaje de utilización) afecta la velocidad del reloj. Dado que las CPU están sincronizadas dinámicamente, esto puede afectar sus resultados. Por ejemplo, si tiene una aplicación de subproceso único, la velocidad de reloj máxima (con TurboBoost) es mayor que para una aplicación que utiliza todos los núcleos. Por lo tanto, esto puede interferir con las comparaciones del rendimiento de subprocesos simples y múltiples en algunos sistemas. Tenga en cuenta que la temperatura y los voltajes también afectan el tiempo que se mantiene la frecuencia Turbo.

Quizás un aspecto más fundamental sobre el que tiene control directo: ¡asegúrese de medir lo correcto! Por ejemplo, si está utilizando System.nanoTime() para comparar un determinado código, coloque las llamadas a la tarea en lugares que tengan sentido para evitar medir cosas que no le interesan. Por ejemplo, no haga:

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

El problema es que no está obteniendo de inmediato la hora de finalización cuando el código ha terminado. En su lugar, intente lo siguiente:

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top