2011-07-13 14 views
25

En Java6 se usaron tanto quicksort como mergesort en Arrays#sort, para matrices primitivas y de objeto, respectivamente. En Java7, ambos han cambiado, a DualPivotQuicksort y Timsort.Java 7 "optimización" de clasificación

En el origen de la nueva ordenación rápida, el siguiente comentario aparece en un par de lugares (por ejemplo, la línea 354):

/* 
    * Here and below we use "a[i] = b; i++;" instead 
    * of "a[i++] = b;" due to performance issue. 
    */ 

¿Cómo es esto un problema de rendimiento? ¿El compilador no reducirá estos a la misma cosa?

Más ampliamente, ¿cuál es una buena estrategia para investigar esto por mi cuenta? Puedo ejecutar benchmarks, pero estaría más interesado en analizar cualquier diferencia en el código compilado. Sin embargo, no sé qué herramientas usar, etc.

+0

O el compilador del punto de acceso ha hecho algo incorrecto (improbable) o los que escribieron el microbenchmark lo arruinaron ... y apuesto a lo último. (Hay muchas razones pequeñas por las que algunos códigos parecen superar a otros, como las páginas de memoria, el tamaño del entorno y lo que no) – bestsss

+0

@bestsss Siempre es posible, por supuesto, pero los tipos que escribieron este código (y posteriormente el comentario) * saben * cómo escribir un punto de referencia. Después de todo, la implementación de la solución rápida de Java ha sido evaluada y ajustada a la muerte. –

+1

FYI, los autores atribuibles de esta clase son Josh Bloch, Jon Bentley (autor de Programming Pearls) y Vladimir Yaroslavskiy –

Respuesta

7

Esto es solo una respuesta a la pregunta general.

Puede mirar el bytecode y tratar de entender las diferencias. Es decir. Puede escribir un ejemplo simple usando a[i] = b; i++; y a[i++] = b; y vea cuál es la diferencia.

La forma más sencilla de mostrar el bytecode es el programa javap (debe incluirse en su JDK). Compile el código con javac SomeFile.java y ejecute javap en el código: javap -c SomeFile (el modificador -c le dice a javap que muestre el bytecode para cada método en el archivo).

Si está utilizando eclipse también puede probar this one.

+0

Gracias - este complemento muestra que el bytecode generado no es el mismo. ¡Ahora para leer sobre cómo leer bytecode! –

+9

No estoy seguro de cuán definitivo es el bytecode. Después de todo, la mayoría de las optimizaciones tienen lugar en el JIT. Yo iría más lejos: el bytecode en este caso es completamente irrelevante, y esta respuesta es engañosa. –

+1

Gracias a las muchas optimizaciones que hace HotSpot, mirar solo el bytecode no dará muchas pistas sobre el rendimiento esperado después de jits. –

1

Hay una manera que le permite ver el processor instructions generated by the hotspot engine.

+0

Me encantaría escuchar el nombre de esa herramienta, que sería extremadamente útil o al menos interesante. – Voo

+0

@Voo, tampoco es una opción de punto de acceso. http://wikis.sun.com/display/HotSpotInternals/PrintAssembly, pero la mejor manera de comprobarlo es simplemente adjuntando el gdb. – bestsss

+0

@bestsss - ¡gracias, eso es lo que estaba buscando! He actualizado mi respuesta ahora. –

5

escribí 2 métodos test1 y test2 y añadir la parte principal del código compilado (Java 1.6 en Snow Leopard) como comentario:

/* 
    *  14 iload_1 [b]  -> load value from address 1 to sack 
    *  15 iastore   -> store value from stack into int array 
    *  16 iinc 3 1 [i]  -> int increment value of address 3 
    *  19 iinc 3 1 [i]  -> int increment value of address 3 
    */ 
    public void test1() { 
     int b = 0; 
     int a[] = new int[10]; 
     for (int i=0; i<10; i++) { 
      a[i] = b; 
      i++; 
     } 
    } 

    /* 
    *  14 iinc 3 1 [i]  -> increment value of address 3 
    *  17 iload_1 [b]  -> load value from address 1 to stack 
    *  18 iastore   -> store value from stack into int array 
    *  19 iinc 3 1 [i]  -> increment value of address 3 
    */ 
    public void test2() { 
     int b = 0; 
     int a[] = new int[10]; 
     for (int i=0; i<10; i++) { 
      a[i++] = b; 
     } 
    } 

El orden de los inc ops es diferente . ¡Pero la suma de la operación de ambos métodos test1 y test2 son iguales! Entonces, el rendimiento de los códigos de bytes también debería ser el mismo.

+2

Es concebible que un optimizador pueda optimizar dos llamadas inc consecutivas en una llamada add $ reg, 2 (que creo que debería ser más rápida al menos en x86?), Lo cual es mucho más difícil para la segunda variante, aún posible, pero tal vez Las optimizaciones actuales de Hotspots no? – Voo