1

私は既存の Java コードから C++ プロジェクトを開発しています。何百万もの整数で構成される同じテスト ファイルから読み取る次の C++ コードと Java コードがあります。

C++:

    int * arr = new int[len]; //len is larger than the largest int from the data
    fill_n(arr, len, -1);  //fill with -1
    long loadFromIndex = 0;
    struct stat sizeResults;
    long size;
    if (stat(fileSrc, &sizeResults) == 0) {
        size = sizeResults.st_size; //here size would be ~551950000 for 552M test file
    }
    mmapFile = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
    long offset = loadFromIndex % pageSize;
    while (offset < size) {
        int i = htonl(*((int *)(mmapFile + offset)));
        offset += sizeof(int);
        int j = htonl(*((int *)(mmapFile + offset)));
        offset += sizeof(int);
        swapElem(i, j, arr);
    }
    return arr;

ジャワ:

    IntBuffer bb = srcFile.getChannel()
                    .map(MapMode.READ_ONLY, loadFromIndex, size)
                    .asIntBuffer().asReadOnlyBuffer();
    while (bb.hasRemaining()) {
        int i = bb.get();
        int j = bb.get();
        swapElem(i, j, arr); //arr is an int[] of the same size as the arr in C++ version, filled with -1
    }
    return arr;

void swapElem(arr)C++ と Java では同じです。配列内の値を比較して変更しますが、元のコードをここに投稿するには長いです。テスト目的で、ループがデッドコードにならないように、次の関数に置き換えました。

void swapElem(int i, int j, int * arr){   // int[] in Java
    arr[i] = j;
}

私は、C++ バージョンが Java バージョンよりも優れているはずだと思っていましたが、テストの結果は逆で、Java コードは C++ コードよりもほぼ 2 倍高速です。C++ コードを改善する方法はありますか?

C ++ のmmapFile+offsetは何度も繰り返されるので、それは O(n) 個の追加であり、 は O(n) 個の追加ですoffset+=sizeof(int)。ここで、n は読み取る整数の数です。Java のIntBuffer.get()場合、バッファのインデックスから直接読み取るだけなので、バッファ インデックスを 1 ずつインクリメントする O(n) 回を除いて加算操作は必要ありません。したがって、バッファ インデックスのインクリメントを含めて、C++ は O(2n) 回の加算を行いますが、Java は O を取得します。 (n) 追加。何百万ものデータになると、パフォーマンスに大きな違いが生じる可能性があります。

この考えに従って、C++ コードを次のように変更しました。

    mmapBin = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
    int len = size - loadFromIndex % pageSize;
    char * offset = loadFromIndex % pageSize + mmapBin;
    int index = 0;
    while (index < len) {
        int i = htonl(*((int *)(offset)));
        offset += sizeof(int);
        int j = htonl(*((int *)(offset)));
        offset += sizeof(int);
        index+=2*sizeof(int);
    }

わずかなパフォーマンスの向上があると想定していましたが、そうではありません。

C++ コードの動作が Java コードよりも遅い理由を誰か説明できますか? ありがとう。

アップデート:

-O2 が機能しないと言ったとき、私の側に問題があったことをお詫びしなければなりません。Makefile を台無しにして、C++ コードが -O2 を使用して再コンパイルされないようにしました。パフォーマンスを更新したところ、-O2 を使用した C++ バージョンが Java バージョンよりもパフォーマンスが向上しました。これで問題は解決しますが、誰かが C++ コードを改善する方法を共有したい場合は、フォローします。一般的には、Java コードよりも 2 倍高速になると予想されますが、現在はそうではありません。ご意見をお寄せいただきありがとうございます。

コンパイラ: g++

フラグ: -Wall -c -O2

Java バージョン: 1.8.0_05

ファイルのサイズ: 552MB、すべて 4 バイト整数

プロセッサー: 2.53 GHz Intel Core 2 Duo

メモリ 4GB 1067 MHz DDR3

更新されたベンチマーク:

バージョン時間(ミリ秒)

C++: ~1100

ジャワ: ~1400

C++ (while ループなし): ~35

Java (while ループなし): ~40

これらのコードの前に、〜 35 ミリ秒のパフォーマンスを引き起こすものがあります (ほとんどの場合、配列は -1 で埋められます) が、ここでは重要ではありません。

4

1 に答える 1