[java] ¿Los compiladores JIT de cualquier JVM generan código que usa instrucciones vectorizadas de punto flotante?



3 Answers

Para abordar algunos de los escepticismos expresados ​​por otros aquí, sugiero que cualquiera que quiera probarse a sí mismo u otros utilice el siguiente método:

  • Crea un proyecto JMH
  • Escribe un pequeño fragmento de matemáticas vectorizable.
  • Ejecute su cambio de referencia entre -XX: -UseSuperWord y -XX: + UseSuperWord (predeterminado)
  • Si no se observa ninguna diferencia en el rendimiento, es probable que tu código no se haya vectorizado
  • Para asegurarse, ejecute su punto de referencia de manera que imprima el conjunto. En Linux, puedes disfrutar del perfilador perfumista ('- prof perfasm') echa un vistazo y mira si las instrucciones que esperas se generan.

Ejemplo:

@Benchmark
@CompilerControl(CompilerControl.Mode.DONT_INLINE) //makes looking at assembly easier
public void inc() {
    for (int i=0;i<a.length;i++)
        a[i]++;// a is an int[], I benchmarked with size 32K
}

El resultado con y sin la bandera (en la computadora portátil Haswell reciente, Oracle JDK 8u60): -XX: + UseSuperWord: 475.073 ± 44.579 ns / op (nanosegundos por opción) -XX: -UseSuperWord: 3376.364 ± 233.211 ns / op

El ensamblaje del bucle caliente tiene mucho que formatear y pegar aquí, pero aquí hay un fragmento (hsdis.so no está formateando algunas de las instrucciones del vector AVX2, así que ejecuté con -XX: UseAVX = 1): -XX: + UseSuperWord (con '-prof perfasm: intelSyntax = true')

  9.15%   10.90%  │││ │↗    0x00007fc09d1ece60: vmovdqu xmm1,XMMWORD PTR [r10+r9*4+0x18]
 10.63%    9.78%  │││ ││    0x00007fc09d1ece67: vpaddd xmm1,xmm1,xmm0
 12.47%   12.67%  │││ ││    0x00007fc09d1ece6b: movsxd r11,r9d
  8.54%    7.82%  │││ ││    0x00007fc09d1ece6e: vmovdqu xmm2,XMMWORD PTR [r10+r11*4+0x28]
                  │││ ││                                                  ;*iaload
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::inc@17 (line 45)
 10.68%   10.36%  │││ ││    0x00007fc09d1ece75: vmovdqu XMMWORD PTR [r10+r9*4+0x18],xmm1
 10.65%   10.44%  │││ ││    0x00007fc09d1ece7c: vpaddd xmm1,xmm2,xmm0
 10.11%   11.94%  │││ ││    0x00007fc09d1ece80: vmovdqu XMMWORD PTR [r10+r11*4+0x28],xmm1
                  │││ ││                                                  ;*iastore
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::inc@20 (line 45)
 11.19%   12.65%  │││ ││    0x00007fc09d1ece87: add    r9d,0x8            ;*iinc
                  │││ ││                                                  ; - psy.lob.saw.VectorMath::inc@21 (line 44)
  8.38%    9.50%  │││ ││    0x00007fc09d1ece8b: cmp    r9d,ecx
                  │││ │╰    0x00007fc09d1ece8e: jl     0x00007fc09d1ece60  ;*if_icmpge

¡Diviértete atacando el castillo?

Question

Digamos que el cuello de botella de mi programa Java realmente es un poco difícil para calcular un montón de productos vector dot. Sí, tengo un perfil, sí, es el cuello de botella, sí, es significativo, sí, así es como funciona el algoritmo, sí, he ejecutado Proguard para optimizar el código de bytes, etc.

El trabajo es, esencialmente, productos punto. Como en, tengo dos float[50] y necesito calcular la suma de los productos pairwise. Sé que existen conjuntos de instrucciones de procesador para realizar este tipo de operaciones de forma rápida y masiva, como SSE o MMX.

Sí, probablemente pueda acceder a ellos escribiendo algún código nativo en JNI. La llamada JNI resulta ser bastante costosa.

Sé que no puedes garantizar lo que un JIT compilará o no compilará. ¿Alguien ha oído hablar alguna vez de un código generador de JIT que utiliza estas instrucciones? y si es así, ¿hay algo sobre el código de Java que ayude a hacerlo compilable de esta manera?

Probablemente un "no"; vale la pena preguntar




Supongo que escribió esta pregunta antes de enterarse de netlib-java ;-) proporciona exactamente la API nativa que necesita, con implementaciones optimizadas para la máquina, y no tiene ningún costo en el límite nativo gracias a la fijación de memoria.




No creo que la mayoría de las máquinas virtuales sean lo suficientemente inteligentes para este tipo de optimizaciones. Para ser justos, la mayoría de las optimizaciones son mucho más simples, como el cambio en lugar de la multiplicación cuando el poder es de dos. El proyecto mono introdujo su propio vector y otros métodos con respaldos nativos para ayudar al rendimiento.




Este es un buen artículo sobre cómo experimentar con las instrucciones de Java y SIMD escritas por mi amigo: prestodb.rocks/code/simd

Su resultado general es que puede esperar que JIT use algunas operaciones SSE en 1.8 (y algunas más en 1.9). Aunque no deberías esperar mucho y debes tener cuidado.




Related