tuning java performance

tuning - java profiler



Extraño rendimiento de bifurcación (1)

Parece una falla menor de JIT. Para una probabilidad de ramificación pequeña, genera algo como lo siguiente, simplemente mucho más complicado debido al desenrollado (estoy simplificando mucho):

movzwl 0x16(%r8,%r10,2),%r9d

Obtenga el carácter: int r9d = queries[r10]

imul $0x8acbf29,%r9d,%ebx

Multiplicar: ebx = 145538857 * r9d

shr $0x1b,%ebx

Shift: ebx >>>= 27

cmp %edx,%ebx jae somewhere

Verificar límites: if (ebx > edx || ebx < 0) goto somewhere (y arrojar allí una IndexOutOfBoundsException .

cmp %r9d,%ebx jne back

Regrese al principio del ciclo si no es igual: if (r9d != ebx) goto back

inc %eax

Incrementa el resultado: eax++

jne back

Simplemente goto back

Podemos ver una cosa inteligente y una tonta:

  • La verificación consolidada se realiza de manera óptima con una sola comparación sin firmar .
  • Es completamente redundante ya que x >>> 27 siempre es positivo y menor que la longitud de la tabla (32).

Para una probabilidad de ramificación superior al 20%, estas tres instrucciones

cmp %r9d,%ebx jne back inc %eax

ser reemplazado por algo así como

mov %eax,%ecx // ecx = result inc %ecx // ecx++ cmp %r9d,%ebx // if (r9b == index) cmoveq %ecx,%ebx // result = ecx

usando una instrucción de movimiento condicional . Esta es una instrucción más, pero no hay ramificación y, por lo tanto, no hay penalización por errores de predicción.

Esto explica el tiempo muy constante en el rango de 20-80%. La rampa por debajo del 20% se debe claramente a errores de predicción de ramas.

Por lo tanto, parece que un JIT no utiliza el umbral adecuado de aproximadamente 0,04 en lugar de 0,18.

Los results de mi benchmark de benchmark muestran que el rendimiento es peor cuando la sucursal tiene un 15% (o un 85%) de probabilidad en lugar de un 50%.

¿Alguna explicación?

El código es demasiado largo pero las partes relevantes están aquí:

private int diff(char c) { return TABLE[(145538857 * c) >>> 27] - c; } @Benchmark int timeBranching(int reps) { int result = 0; while (reps-->0) { for (final char c : queries) { if (diff(c) == 0) { ++result; } } } return result; }

Cuenta el número de caracteres BREAKING_WHITESPACE en la cadena dada. Los resultados muestran una caída repentina de tiempo (aumento de rendimiento) cuando la probabilidad de ramificación alcanza aproximadamente 0,20.

Más details sobre la caída. La variación de la semilla muestra que ocurren más cosas extrañas. Tenga en cuenta que la línea negra que indica los valores mínimo y máximo es muy corta, excepto cuando está cerca del acantilado.