2011-11-02 45 views
13

我想比较原始指针,boost shared_ptr和boost weak_ptr之间的性能。在解引用部分,我期望shared_ptr和raw_ptr是相等的,但结果显示shared_ptr大约是速度的两倍。对于测试,我建立与任一指针的数组或共享指针整数,然后在这样的环路解引用:Boost 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整数,但也可以通过i+=2而不是++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; 
} 

顺便提及,使用boost::make_shared<int>(i)代替PtrT(new int(I))在存储器而不是在不同的地点一起分配的引用计数和对象。在我的测试中,这改善了共享指针取消引用的性能约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个引用计数的数据结构的指针,一个指针,一个删除器,甚至可能是一个互斥量(希望不是)。 – curiousguy

+3

@curious大小是2个指针 - 一个是真正的有效载荷,一个是开销。但这些都不影响简单威慑的成本。 –

+0

啊,非常感谢!我会调整我的测试,使比较更公平。 –

相关问题