2011-11-02 11 views
13

私は生ポインタ間のパフォーマンスを比較しようとしています。これは、shared_ptrをブーストし、weak_ptrをブーストします。逆参照部分では、shared_ptrとraw_ptrが等しいと予想しましたが、結果はshared_ptrが約2倍遅いことを示しています。テストのために、私はint型へのポインタまたは共有ポインタのいずれかの配列を作成していますし、このようなループ内でデリファレンス:ブーストshared_ptr逆参照コスト

int result; 
for(int i = 0; i != 100; ++i) 
{ 
    for(int i = 0; i != SIZE; ++i) 
    result += *array[i]; 
} 

テストのための完全なコードはここで見つけることができます: https://github.com/coolfluid/coolfluid3/blob/master/test/common/utest-ptr-benchmark.cpp

アサーションのない最適化されたビルドの

テストタイミングは、ここで見つけることができます:関心の http://coolfluidsrv.vki.ac.be/cdash/testDetails.php?test=145592&build=7777

値は「DerefShared時間」と「DerefRaw時間」です

私はテストに何らかの欠陥があるかもしれないと思いますが、違いがどこにあるのか理解できませんでした。プロファイリングでは、shared_ptrの演算子*がインライン展開されていることを示しています。時間がかかるようです。ブーストアサーションがオフであることを再確認しました。

誰かが違いがどこから来るのか説明できるのであれば、非常に感謝します。

追加のスタンドアロンテスト: https://gist.github.com/1335014

+0

+1、私も先日このことについて考えていました。 –

+7

キャッシュ効果? shared_ptrは生のポインタよりも大きいので、あなたの配列はより多くのキャッシュラインをカバーし、読み込みに時間がかかります。 –

+0

これらのテストはどのプラットフォームで実行していますか? – SoapBox

答えて

10

はアラン・ストークスは、彼のコメントで述べたように、これはキャッシュの影響によるものです。共有ポインタには、参照カウントが含まれています。つまり、実際のポインタよりもメモリが物理的に大きいことを意味します。連続した配列に格納すると、キャッシュラインあたりのポインタが少なくなります。つまり、ループはローポインタの場合よりもメインメモリに頻繁に出なければなりません。

生ポインタテストでSIZE*2 intsを割り当てるだけでなく、++iの代わりにi+=2でストライドになるように参照解除ループを変更することで、この動作を確認できます。これを行うことで、私のテストでほぼ同じ結果が得られました。生のテストのための私のコードは以下の通りです。代わりPtrT(new int(I))boost::make_shared<int>(i)を用いなお

#include <iostream> 
#include <boost/timer.hpp> 

#define SIZE 1000000 

typedef int* PtrT; 

int do_deref(PtrT* array) 
{ 
    int result = 0; 
    for(int i = 0; i != 1000; ++i) 
    { 
     for(int i = 0; i != SIZE*2; i+=2) 
      result += *array[i]; 
    } 

    return result; 
} 

int main(void) 
{ 
    PtrT* array = new PtrT[SIZE*2]; 
    for(int i = 0; i != SIZE*2; ++i) 
     array[i] = new int(i); 
    boost::timer timer; 
    int result = do_deref(array); 
    std::cout << "deref took " << timer.elapsed() << "s" << std::endl; 
    return result; 
} 

は、メモリ内ではなく、別の場所で一緒に参照カウントとオブジェクトを割り当てます。私のテストでは、共有ポインタ逆参照のパフォーマンスが約10〜20%向上しました。そのためのコードは以下の通りです:

#include <iostream> 
#include <boost/timer.hpp> 
#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 
#define SIZE 1000000 

typedef boost::shared_ptr<int> PtrT; 

int do_deref(PtrT* array) 
{ 
    int result = 0; 
    for(int j = 0; j != 1000; ++j) 
    { 
     for(int i = 0; i != SIZE; ++i) 
      result += *array[i]; 
    } 

    return result; 
} 

int main(void) 
{ 
    PtrT* array = new PtrT[SIZE]; 
    for(int i = 0; i != SIZE; ++i) 
     array[i] = boost::make_shared<int>(i); 
    boost::timer timer; 
    int result = do_deref(array); 
    std::cout << "deref took " << timer.elapsed() << "s" << std::endl; 
    return result; 
} 

私の結果(x86-64のUnbuntu 11 VM):

Original Raw: 6.93 
New Raw: 12.9 
Original Shared: 12.7 
New Shared: 10.59 
+4

"_Sharedポインタには参照カウントが含まれています_は、実際には2回の参照カウント、ポインタ、デリター、おそらくmutex(おそらくはない)を持つデータ構造体へのポインタです。 – curiousguy

+3

@curiousサイズは2ポインタです - 実際のペイロードに1つ、オーバーヘッドに1つです。しかし、それは単純な抑止のコストに影響しません。 –

+0

ああ、多くの感謝!比較をより公正にするために私のテストを適応させます。 –

関連する問題