2

2 つの主要な段階がある長いプロセスがあります。第 1 段階と第 2 段階では、実行パスが若干異なります。

-serverJMH ( , on )によると、同じメソッドのコピーを別の名前で作成し、各段階で別の名前を使用するとjava-7-openjdk-amd64、第 2 段階でメソッド呼び出しが 25% 以上高速化されることに気付きました (メソッドへの数百万回の呼び出し (5 回の呼び出しのウォームアップ後に 5 回の呼び出しで測定)。

メソッドに関する以前の最適化を忘れて、ゼロから再学習するように JVM に指示する方法はありますか?

次のコード例では、ベンチマーク メソッドはであり、とrunを呼び出す 2 つのバージョン間で比較が行われます。checkCharcheckChar0stage2

final public void run(){
   sumStg1=0;
   for(int i=0; i< 10000; i++){
      String str = consumeString();
      for(int i= 0; i<K; i++){
         sumStg1 += checkChar(str.charAt(i), i)?1:0;
      }
   }

   sumStg2=0;
   for(int j=0; j< 10000000; j++){
      String str = consumeString();
      for(int i=K/2; i<str.length(); i++){
         sumStg2 += checkChar(str.charAt(i), i)?1:0;
      }
   }
}

final public boolean checkChar(char in, int i){
   if(i < K/2){
     ...
   } else if (i < K){
     ...
   } else {
     ...
   }
}

//identical method to checkChar
final public boolean checkChar0(char in, int i){
   if(i < K/2){
     ...
   } else if (i < K){
     ...
   } else {
     ...
   }
}
4

2 に答える 2

0

次の 2 つのアイデアが思い浮かびます。

A)変更可能な Cal​​lSiteを介してメソッドを呼び出し、同じメソッドを指す新しいメソッド ハンドルで更新してからsyncAll()を呼び出すと、呼び出し元のメソッドの再コンパイルがトリガーされます。

SwitchPointは同様の機能を提供します

私が知らないのは、メソッドがそれ自体で置き換えられた場合に再コンパイルをスキップして、JVM がここで巧妙さを適用するかどうかです。

B)メソッド本体などに不活性なバイトコードを追加することを除いて、本質的に何も変更しないクラスファイルの再変換を適用します。

私はこれを試していないので、保証するものではないことに注意してください。


ベンチマークしようとしているものをベンチマークしていない可能性もあります。JMH は、コードに手をかざすだけですべての測定問題が解決する魔法の杖ではありません。

実際のアプリケーションは 2 つのフェーズで構成されており、1 つのフェーズ遷移があるとのことです。

しかし、JMH では、全体で 10 回の反復 (それぞれ N 回の呼び出し) を使用しています。これは、新しい反復の開始時に 10*N 回の順方向フェーズ遷移と 10*N 回の逆方向遷移を意味します。これにより、最終的に JIT が再コンパイルを断念することになります。

JMH は、アプリケーションが 1 回限りの動作に依存している間、定常状態のパフォーマンスを測定するように設計されています。

于 2015-07-26T06:22:19.993 に答える
0

別のアイデアのカップル:

  • クラスを新しいクラスローダーに再度ロードし、静的にロードされたバージョンの代わりにそのバージョンを使用します。

  • にもっと大きな値を設定します-XX:CompileThreshold

(これらには両方とも重大な/明らかな欠点がありますが、パフォーマンスがそれほど重要な場合は....)

于 2015-07-26T06:26:58.690 に答える