我正在尝试比较原始指针, boost shared_ptr和 boost weak_ptr的性能。在取消引用部分,我希望shared_ptr和raw_ptr相等,但是结果表明shared_ptr的速度大约是原来的两倍。为了进行测试,我创建了一个包含指向int的指针或共享指针的数组,然后在这样的循环中取消引用:

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 time”和“DerefRaw time”

我猜测试可能有某种缺陷,但我无法弄清楚差异的出处。分析显示,shared_ptr中的运算符*已内联,这似乎需要更多时间。我仔细检查了boost断言是否关闭。

如果有人能解释差异的根源,我将不胜感激。

其他独立测试:
https://gist.github.com/1335014

最佳答案

正如艾伦·斯托克斯(Alan Stokes)在评论中所说,这是由于缓存效应所致。共享指针包含一个引用计数,这意味着它们在内存上比原始指针要大。当存储在连续数组中时,每个高速缓存行获得的指针更少,这意味着循环必须比原始指针更频繁地进入主内存。

在原始指针测试中,您可以通过分配SIZE*2 int来观察此行为,还可以将取消引用循环更改为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))会将引用计数和对象一起分配在内存中,而不是在单独的位置。在我的测试中,这将共享指针取消引用的性能 boost 了约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

关于c++ - 增加shared_ptr取消引用成本,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7987532/

10-11 23:14
查看更多