1

私は小さなテストを実行していますが、マイクロ ベンチマークではありますが、本番環境で実際に行っていることをかなりうまく模倣しています。

私は 2D 配列、5 列、10,000,000 行を作成しており、0 から 19 までのランダムな整数で埋められています。次に、2 列目の値が偶数である限り、3 列目のすべての数値を合計します。これを 100 回行ってウォームアップし、さらに 100 回行って、所要時間を計測します。

私のマシンでは、大部分の時間は約 9 秒かかりますが、6 秒弱かかることもあります。

ガベージ コレクションや JIT コンパイルのようには見えません。

非常にまれに非常に高速になる理由を誰かが知っていますか?

これらの引数を使用して Linux で JDK7u11 を使用してコードを実行します。 8) これらのパラメータをすべて削除しても、タイミングに大きな影響はないようです。

コードは次のとおりです。

import java.util.ArrayList;
import java.util.Random;

public class JavaPerformanceTest {
    public static void main(String[] args) {
        int numColumns = 5;
        int numRows = 10000000;
        int[][] data = new int[numColumns][numRows];
        Random rand = new Random(1234);
        for (int j = 0; j < numColumns; j++) {
            for (int i = 0; i < numRows; i++) {
                data[j][i] = rand.nextInt(20);
            }
        }
        int warmUp = 100;
        ArrayList<Integer> sums = new ArrayList<Integer>();
        System.out.println("warm up " + warmUp + " times");
        long warmUpStart = System.nanoTime();
        for (int i = 0; i < warmUp; i++) {
            sums.add(sum(numRows, data));
        }
        long warmUpEnd = System.nanoTime();
        System.out.println("warm up complete " + (warmUpEnd - warmUpStart) / 1000000);
        int numberOfRuns = 100;
        int finalSum = 0;
        long startTime = System.nanoTime();
        for (int i = 0; i < numberOfRuns; i++) {
            finalSum = sum(numRows, data);
        }
        long endTime = System.nanoTime();
        long diff = (endTime - startTime) / 1000000;
        System.out.println("Time taken: " + diff + "    Sum: " + finalSum);
    }


    public static int sum(int numRows, int[][] columnBased) {
        int sum = 0;
        for (int i = 0; i < numRows; i++) {
            if ((columnBased[1][i] % 2) == 0) {
                sum += columnBased[2][i];
            }
        }
        return sum;
    }
}

ありがとう、ニック。

4

1 に答える 1

1

パフォーマンスの低下には、キャッシュ ミスや分岐予測の失敗など、さまざまな原因が考えられます。コードが最適であることを確認してから、結果が安定するように繰り返します。

import java.util.ArrayList;
import java.util.Random;

public class JavaPerformanceTest {
    public static void main(String[] args) {
        int numColumns = 5;
        int numRows = 10000000;
        byte[][] data = new byte[numColumns][numRows];
        Random rand = new Random(1234);
        for (int j = 0; j < numColumns; j++) {
            for (int i = 0; i < numRows; i++) {
                data[j][i] = (byte) rand.nextInt(20);
            }
        }
        int warmUp = 10;
        ArrayList<Integer> sums = new ArrayList<Integer>();
        System.out.println("warm up " + warmUp + " times");
        long warmUpStart = System.nanoTime();
        for (int i = 0; i < warmUp; i++) {
            sums.add(sum(numRows, data));
        }
        long warmUpEnd = System.nanoTime();
        System.out.println("warm up complete " + (warmUpEnd - warmUpStart) / 1000000);
        for (int t = 0; t < 3; t++) {
            int numberOfRuns = 100;
            int finalSum = 0;
            long startTime = System.nanoTime();
            for (int i = 0; i < numberOfRuns; i++) {
                finalSum = sum(numRows, data);
            }
            long endTime = System.nanoTime();
            long diff = (endTime - startTime) / 1000000;
            System.out.println("Time taken: " + diff + "    Sum: " + finalSum);
        }
    }


    public static int sum(int numRows, byte[][] columnBased) {
        int sum = 0;
        byte[] col1 = columnBased[1];
        byte[] col2 = columnBased[2];
        for (int i = 0; i < numRows; i++)
            // use multiplication instead of "if" to avoid branch prediction failures
            sum += ((col1[i] + 1) & 1) * col2[i];
        return sum;
    }
}

版画

warm up 10 times
warm up complete 109
Time taken: 1006    Sum: 47505460
Time taken: 1006    Sum: 47505460
Time taken: 1026    Sum: 47505460

要約すると、コードを最適化すると、コマンド ライン パラメーターをいじるよりもはるかにパフォーマンスが向上します。

于 2013-04-25T10:54:49.417 に答える