recompilaciones JIT hacer tiro rápido después de más iteraciones si StackTrace es de longitud incluso

Adwait Kumar:

El siguiente código,

public class TestFastThrow {

    public static void main(String[] args) {
        int count = 0;
        int exceptionStackTraceSize = 0;
        Exception exception = null;
        do {
            try {
                throwsNPE(1);
            }
            catch (Exception e) {
                exception = e;
                if (exception.getStackTrace().length != 0) {
                    exceptionStackTraceSize = exception.getStackTrace().length;
                    count++;
                }
            }
        }
        while (exception.getStackTrace().length != 0);
        System.out.println("Iterations to fastThrow :" + count + ", StackTraceSize :" + exceptionStackTraceSize);
    }

    static void throwsNPE(int callStackLength) {
        throwsNPE(callStackLength, 0);
    }

    static void throwsNPE(int callStackLength, int count) {
        if (count == callStackLength) {
            ((Object) null).getClass();
        }
        else {
            throwsNPE(callStackLength, count + 1);
        }
    }

}

da el siguiente resultado después de ejecutar varias veces,

Iterations to fastThrow :5517, StackTraceSize :4
Iterations to fastThrow :2825, StackTraceSize :5
Iterations to fastThrow :471033, StackTraceSize :6
Iterations to fastThrow :1731, StackTraceSize :7
Iterations to fastThrow :157094, StackTraceSize :10
.
.
.
Iterations to fastThrow :64587, StackTraceSize :20
Iterations to fastThrow :578, StackTraceSize :29

detalles de la MV

Java HotSpot(TM) 64-Bit Server VM (11.0.5+10-LTS) for bsd-amd64 JRE (11.0.5+10-LTS)
-XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -XX:+PrintAssembly

Lo que es sorprendente es la razón por qué el JIT se necesita mucho más iteraciones para Optimizar si el seguimiento de la pila es de longitud impar?

He activado JIT Registros y analizado a través de jitwatch, pero no pude ver nada útil, al igual que la línea de tiempo de compilación cuando el C1 y C2 que parece estar pasando después por las stacktraces tamaño aún.

Línea de tiempo es algo como esto, (mirando cuando java.lang.Throwable.getStackTrace()se compila)

| StackSize     | 10    | 11    |
|---------------|-------|-------|
| Queued for C1 | 1.099 | 1.012 |
| C1            | 1.318 | 1.162 |
| Queued for C2 | 1.446 | 1.192 |
| C2            | 1.495 | 1.325 |

¿Por qué es esto ocurra? Y lo que hace el uso heurística JIT para tiro rápido?

apangin:

Este efecto es el resultado de difícil compilación niveles y la política de inclusión entre líneas .

Voy a explicar en el ejemplo simplificado:

public class TestFastThrow {

    public static void main(String[] args) {
        for (int iteration = 0; ; iteration++) {
            try {
                throwsNPE(2);
            } catch (Exception e) {
                if (e.getStackTrace().length == 0) {
                    System.out.println("Iterations to fastThrow: " + iteration);
                    break;
                }
            }
        }
    }

    static void throwsNPE(int depth) {
        if (depth <= 1) {
            ((Object) null).getClass();
        }
        throwsNPE(depth - 1);
    }
}

Por simplicidad, voy a excluir a todos los métodos de compilación, excepto throwsNPE.

-XX:CompileCommand=compileonly,TestFastThrow::throwsNPE -XX:+PrintCompilation
  1. HotSpot utiliza gradas de la compilación por defecto. Aquí throwsNPEse compila primero en el Nivel 3 (C1 con perfiles). Perfilado en C1 hace posible volver a compilar el método más tarde por C2.

  2. OmitStackTraceInFastThrowoptimización funciona sólo en C2 código compilado. Por lo tanto, cuanto antes se compila el código de C2 - los menos iteraciones pasarán antes de que termine el bucle.

  3. Cómo perfiles en las obras código compilado-C1: se incrementa el contador en cada invocación de métodos y en cada rama hacia atrás (sin embargo, no hay ramas hacia atrás en throwsNPEel método). Cuando el contador alcanza cierto umbral configurable, la política de recopilación JVM decide si las necesidades método actual para volver a compilar.

  4. throwsNPEes un método recursivo. HotSpot puede inline llamadas recursivas hasta -XX:MaxRecursiveInlineLevel(valor por defecto es 1).

  5. La frecuencia con qué frecuencia las llamadas C1 código compilado atrás a la política de recopilación de JVM, es diferente para las invocaciones regulares frente a invocaciones inline. A notifica método regular JVM cada 2 10 invocaciones ( -XX:Tier3InvokeNotifyFreqLog=10), mientras que los notifica inline método JVM mucho más raramente: cada 2 20 invocaciones ( -XX:Tier23InlineeNotifyFreqLog=20).

  6. Para el número par de llamadas recursivas, todas las invocaciones siguen Tier23InlineeNotifyFreqLogparámetro. Cuando el número de llamadas es impar, procesos en línea no funciona para la última llamada de sobra, y esta última invocación siguiente Tier3InvokeNotifyFreqLogparámetro.

  7. Este medio, cuando la profundidad llamada es par, throwsNPEse volverá a compilar sólo después de 2 20 llamadas, es decir, después de 2 19 iteraciones del bucle. Eso es exactamente lo que usted verá cuando se ejecuta el código anterior con throwNPE(2):

    Iterations to fastThrow: 524536
    

    524 536 está muy cerca de 2 19 = 524288

    Ahora, si ejecuta la misma aplicación con -XX:Tier23InlineeNotifyFreqLog=15el número de iteraciones será cercano a 2 14 = 16.384.

    Iterations to fastThrow: 16612
    
  8. Ahora vamos a cambiar el código para llamar throwsNPE(1). El programa terminará muy rápidamente, sin tener en cuenta Tier23InlineeNotifyFreqLogel valor. Esto se debe a la diferente opción gobierna ahora. Pero si yo vuelva a ejecutar el programa con -XX:Tier3InvokeNotifyFreqLog=20el bucle finalizará no antes de después de 2 20 iteraciones:

    Iterations to fastThrow: 1048994
    

Resumen

Optimización de tiro rápido se aplica sólo al código compilado-C2. Debido a un nivel de inclusión entre líneas ( -XX:MaxRecursiveInlineLevel), compilación C2 se activa antes (después de 2 Tier3InvokeNotifyFreqLog invocaciones, si el número de llamadas recursivas es impar), o más tarde (después de 2 Tier23InlineeNotifyFreqLog invocaciones, si todas las llamadas recursivas están cubiertos por inline).

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=364987&siteId=1
Recomendado
Clasificación