スタックトレースが偶数長である場合にJITは、より多くの反復後に高速スローを行うことを再コンパイル

Adwaitクマール:

次のコードは、

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);
        }
    }

}

複数回実行した後、次の出力が得られます、

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

VMの詳細

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

何を驚くべきものであったが、スタックトレースが偶数の長さであれば、なぜJITを最適化するために、より多くの反復を取るんでしょうか?

私は、JITログを有効にしてjitwatchを介して分析が、ちょうどC1とC2コンパイルもサイズのスタックトレースのために、後に起こっているように見えるときのタイムラインという、有用何も表示されませんでした。

タイムラインは、このようなものである、(ときを見てjava.lang.Throwable.getStackTrace()コンパイルされています)

| 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 |

なぜ、まさにこの出来事はありますか?そして、何ヒューリスティックは速い投球のためのJITの使用していますか?

apangin:

この効果は、トリッキーの結果である階層型コンパイルとインライン化方針

私は簡単な例で説明しましょう:

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);
    }
}

簡単にするために、私は除いて、コンパイルからのすべてのメソッドを除外しますthrowsNPE

-XX:CompileCommand=compileonly,TestFastThrow::throwsNPE -XX:+PrintCompilation
  1. ホットスポットは、デフォルトでは階層型コンパイルを使用しています。ここでthrowsNPE第一層3(プロファイリングとC1)でコンパイルされます。C1にプロファイリングするC2によって後者の方法を再コンパイルすることが可能となります。

  2. OmitStackTraceInFastThrow最適化は、C2のみコンパイルされたコードで動作します。だから、早くコードがC2でコンパイルされた - 以下の反復は、ループが終了する前に通過します。

  3. どのようにプロファイリングC1-コンパイルされたコードの作品に:カウンタは、すべてのメソッド呼び出しで、すべての後方分岐にインクリメントされ(ただし、には後方の支店がないthrowsNPE方法)。カウンタは、特定の設定可能なしきい値に達したときに、JVMコンパイルポリシーは、現在の方法は、再コンパイルする必要があるかどうかを決定します。

  4. throwsNPE再帰的な方法です。ホットスポットは、最大再帰呼び出しをインライン化することができます-XX:MaxRecursiveInlineLevel(デフォルト値は1です)。

  5. C1コンパイルされたコードの呼び出しは、JVMのコンパイルポリシーにバックアップする頻度頻度、インライン化呼び出し対通常の呼び出しのために異なります。通常の方法を通知は、すべて2つのJVM 10の呼び出し(-XX:Tier3InvokeNotifyFreqLog=10すべての2:はるかにまれJVMに通知するインライン方式しばらく)、20呼び出しを(-XX:Tier23InlineeNotifyFreqLog=20)。

  6. 再帰呼び出しの数が偶数の場合は、すべての呼び出しが続くTier23InlineeNotifyFreqLogパラメータを。呼び出しの数が奇数の場合、インライン化は、最後の残りの呼び出しのためではない仕事をしており、この最後の呼び出しは、以下のTier3InvokeNotifyFreqLogパラメータを。

  7. コールの深さが偶数の場合、この手段は、throwsNPE後にのみ2つの再コンパイルされます20 2の後、すなわち通話を19ループの反復。それはあなたが上記のコードを実行したときに表示されます正確に何ですthrowNPE(2)

    Iterations to fastThrow: 524536
    

    524536は、2に非常に近い19 = 524288

    あなたと同じアプリケーションを実行する場合さて、-XX:Tier23InlineeNotifyFreqLog=15反復回数は2に近いだろう14 = 16384。

    Iterations to fastThrow: 16612
    
  8. 今度は、呼び出すためのコードを変更してみましょうthrowsNPE(1)プログラムは関係なく、非常に迅速に終了しますTier23InlineeNotifyFreqLog値。今別のオプションルールだからです。私は、プログラムを再実行した場合でも-XX:Tier3InvokeNotifyFreqLog=20、ループが2後より早くない仕上がりになる20回の反復:

    Iterations to fastThrow: 1048994
    

概要

高速スロー最適化は唯一のC2-コンパイルされたコードに適用されます。インライン化の1つのレベル(に-XX:MaxRecursiveInlineLevel)、C2のコンパイルがトリガされる以前(2つの後Tier3InvokeNotifyFreqLogの呼び出し、再帰呼び出しの数が奇数の場合)後、又は(2つの後Tier23InlineeNotifyFreqLogを呼び出し、すべての再帰呼び出しをインライン化することによって覆われている場合)。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=364984&siteId=1