0

次の Java ソースを検討してください。

package com.stackoverflow;

 public class CondSpeed {
 private static final long COUNT = 1000000000;
 private static final long OUTER_COUNT = 15;

 private static long notEqOperator = 0L;
  private static long notOperator = 0L;
private static long equalsFalse = 0L;

public CondSpeed() {
 super();
}

public static void main(String[] args) {

 for(int outCount = 0;outCount < OUTER_COUNT;outCount++){
  notEqOperator += testNotEaualsOperator();
  equalsFalse += testEqualFalse();
  notOperator += testNotOperator();
 }

 long avrForNotEqOperator = (notEqOperator / OUTER_COUNT);
 long avrForEqualsFalse = (equalsFalse / OUTER_COUNT);
 long avrForNotOperator = (notOperator / OUTER_COUNT);

 System.out.println("Avr for Not Equals Operator: "+avrForNotEqOperator);
 System.out.println("Avr for Equals \"false\" Operator: "+avrForEqualsFalse);
 System.out.println("Avr for Not Operator: "+avrForNotOperator);

}

private static long testEqualFalse(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse == false){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}


   private static long testNotOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(!truFalse){
//do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static long testNotEaualsOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse != true){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static boolean isFalse;
private static boolean returnTrueOrFalse(){
 if(isFalse){
  isFalse = false;
 }
 else{
  isFalse = true;
 }
 return isFalse;
}

}

ご覧のとおり、これは 3 つのバージョンのif(false)条件に対するテストです。

  • さまざまな条件ステートメントで最初に結果が異なる理由に興味があります。((明らかに、コンパイラが .java をバイトコードに解釈する方法であることはわかっています。)) これ以上のことはありますか?
  • 第二に。さまざまな Hotspot VM の違いを見てください。下を参照してください。これは、バージョンを超えた VM の更新/改善によるものですか? それともそれ以上のものがありますか?
  • これは、このようなものをテストするための最良の方法ですか?

---結果 Mac OS X ---

JavaVM ホットスポット 1.6.0

Not Equals 演算子の Avr: 1937
Equals "false" 演算子の Avr: 1937
Not Operator の Avr: 1941

JavaVM ホットスポット 1.5.0

Not Equals 演算子の Avr: 5023
Equals "false" 演算子の Avr: 5035
Not Operator の Avr: 5067

JavaVM ホットスポット 1.4.2

Not Equals 演算子の Avr: 3993
Equals "false" 演算子の Avr: 4015
Not Operator の Avr: 4009

JavaVM ホットスポット 1.4.0

Not Equals 演算子の Avr: 3961
Equals "false" 演算子の Avr: 3960
Not Operator の Avr: 3961

ありがとう。

4

3 に答える 3

4

!、!=、== の違いはランダム ノイズのように見えます。まったく同じミリ秒数になると本当に予想していましたか?

ただし、JVM バージョンでの改善は、その特定のコードに非常に固有のものである可能性が高いものの、ほぼ確実に現実のものであり、適切に処理される複雑さのしきい値内に何かが収まるかどうかの問題です。わずかに異なるものでも、同じ結果が得られない場合があります。

テストを改善するには、各テスト実行の標準偏差を計算し、それらが統計的に異なるかどうかを確認します (または、10 個の結果すべてを印刷して目で確認します)。

于 2009-09-05T10:31:32.483 に答える
2

JVM がまともな仕事をしている場合、次のステートメントが計算に影響を与えず、それらを完全に最適化しないことを検出します。

if (truFalse != true) {
     //do nothing...
}
...
if (truFalse == false) {
   //do nothing...
}
...
if (!truFalse) {
   //do nothing...
}

つまり、ベンチマークは、おそらく 3 つのケースで異なるものを測定していません。

学ぶべき教訓:

  1. マイクロベンチマークから意味のある数値を取得していることを確認するのは困難です。
  2. 相対数は、JVM ごとに大きく異なる場合があります。ある JVM で役立つ「巧妙なトリック」が、実際には別の JVM では邪魔になる可能性があります。
  3. コンパイラは、プラットフォームごとに Java プログラムをマイクロ最適化するという点で、あなたよりもはるかに優れた仕事をする可能性があります。

最適な戦略は、マイクロ最適化をコンパイラーに任せ、最適なアルゴリズムを使用するなどの「マクロ」の問題に集中することです。また、実行プロファイラーを使用して、時間をかけて最適化する価値のある場所を特定します。

于 2009-09-05T13:20:48.283 に答える
2

このようなマイクロベンチマークでは、興味深いことは何もわかりません。テストを 10 億回繰り返して、結果が数秒で返ってきます。それは反復ごとに何サイクルですか?マイクロベンチマークは機能していません。

于 2009-09-05T10:21:01.600 に答える