2016-03-20 10 views
0

私は現在、任意のジョブを実行する大規模ループのさまざまな実装をベンチマークしようとしています。ブーストトランスレーションイテレータとboosting countingerを使用すると非常に遅いバージョンが見つかりました。boost transformeriteratorとcounting_iteratorのパフォーマンス上の問題

0とSIZE-1の間のすべての整数の積を任意の整数(私の例ではオーバーフローを避けるために1にすることを選択したもの)で合計する2つのループをベンチマークする小さなコードを設計しました。

彼女は私のコードです:

//STL 
#include <iostream> 
#include <algorithm> 
#include <functional> 
#include <chrono> 

//Boost 
#include <boost/iterator/transform_iterator.hpp> 
#include <boost/iterator/counting_iterator.hpp> 

//Compile using 
// g++ ./main.cpp -o test -std=c++11 

//Launch using 
// ./test 1 

#define NRUN 10 
#define SIZE 128*1024*1024 

struct MultiplyByN 
{ 
    MultiplyByN(size_t N): m_N(N){}; 
    size_t operator()(int i) const { return i*m_N; } 
    const size_t m_N; 
}; 

int main(int argc, char* argv[]) 
{ 
    int N = std::stoi(argv[1]); 
    size_t sum = 0; 
    //Initialize chrono helpers 
    auto start = std::chrono::steady_clock::now(); 
    auto stop = std::chrono::steady_clock::now(); 
    auto diff = stop - start; 
    double msec=std::numeric_limits<double>::max(); //Set min runtime to ridiculously high value 
    MultiplyByN op(N); 


    //Perform multiple run in order to get minimal runtime 
    for(int k = 0; k< NRUN; k++) 
    { 
     sum = 0; 
     start = std::chrono::steady_clock::now(); 
     for(int i=0;i<SIZE;i++) 
     { 
      sum += op(i); 
     } 
     stop = std::chrono::steady_clock::now(); 
     diff = stop - start; 
     //Compute minimum runtime 
     msec = std::min(msec, std::chrono::duration<double, std::milli>(diff).count()); 
    } 
    std::cout << "First version : Sum of values is "<< sum << std::endl; 
    std::cout << "First version : Minimal Runtime was "<< msec << " msec "<< std::endl; 
    msec=std::numeric_limits<double>::max(); //Reset min runtime to ridiculously high value 

    //Perform multiple run in order to get minimal runtime 
    for(int k = 0; k< NRUN; k++) 
    { 
     start = std::chrono::steady_clock::now(); 

     //Functional way to express the summation 
     sum = std::accumulate( boost::make_transform_iterator(boost::make_counting_iterator(0), op), 
         boost::make_transform_iterator(boost::make_counting_iterator(SIZE), op), 
         (size_t)0, std::plus<size_t>()); 

     stop = std::chrono::steady_clock::now(); 
     diff = stop - start; 
     //Compute minimum runtime 
     msec = std::min(msec, std::chrono::duration<double, std::milli>(diff).count()); 
    } 
    std::cout << "Second version : Sum of values is "<< sum << std::endl; 
    std::cout << "Second version version : Minimal Runtime was "<< msec << " msec "<< std::endl; 
    return EXIT_SUCCESS; 
} 

そして私が手出力:

./test 1 
First version : Sum of values is 9007199187632128 
First version : Minimal Runtime was 433.142 msec 
Second version : Sum of values is 9007199187632128 
Second version version : Minimal Runtime was 10910.7 msec 

STDを使用して、私のループの「機能」バージョン::蓄積は、単純なループよりも25倍遅いですバージョン、なぜそう?

は、コード内のコメントをもとに、あなたの助け

+0

コンパイラの最適化を有効にしてコンパイルしましたか? (gccとclangの-O2、MSCVのリリースビルド)そうしないと結果は無意味です。 –

+2

私はgcc(C++ 14)をブースト1.60と "-o2"で試してみました - そして、2番目のバージョンは実行するたびに少し速くなりました....(121msと118ms)... – PiotrNycz

答えて

1

のために事前にありがとうあなたが++のデフォルトを使用グラム、最適化レベルを指定しなかったので、あなたは

g++ ./main.cpp -o test -std=c++11 

でこれをまとめました-O0つまり最適化なしです。

これは、コンパイラが何もインライン化していないことを意味します。標準ライブラリやブーストのようなテンプレートライブラリは、パフォーマンスのためのインライン展開に依存します。さらに、コンパイラは余分なコードをたくさん生成します。これは最適ではありません。そのようなバイナリでパフォーマンスを比較するのは意味がありません。

最適化を有効にして再コンパイルし、再度テストを行って意味のある結果を得てください。

+0

パフォーマンスは確かに多かった-O3フラグでうまくいくと、このフラグを使って両方の方法で約100msを得ました。ありがとうございました – Tobbey

関連する問題