是std :: get<>和std :: tuple<>比原始指针慢?

时间:2016-01-28 20:56:13

标签: c++11 stdtuple

我有一个C ++ 11应用程序,我通常迭代几种不同的数组结构用于各种算法。原始CPU性能对此应用程序很重要。

数组元素是基本类型(int,double,..)或简单结构。该阵列通常是数万个元素。我经常需要在给定的循环中一次迭代几个数组。所以通常我需要一个指针用于任何类型的每个数组。所以我需要增加五个单独的指针,这是冗长的。

基于这些关于元组的答案, Why is std::pair faster than std::tuple C++11 tuple performance 我希望使用元组将指针打包到一个对象中没有任何开销。

我认为实现像对象这样的游标以协助迭代可能会很好,因为错过特定指针的增量会是一个烦人的错误。

auto pts = std::make_tuple(p1, p2, p3...);

允许您以类型安全的方式将一堆变量捆绑在一起。然后,您可以实现一个可变参数模板函数,以类型安全的方式递增元组中的每个指针。

...然而

当我测量性能时,元组版本比使用原始指针要慢。但是当我查看生成的程序集时,我在元组循环增量中看到了额外的mov指令。也许是因为std::get<>返回引用的事实?我本以为会被编译掉......

我是否遗漏了某些东西,或者是在使用这样的时候打败元组的原始指针?这是一个简单的测试工具。我抛弃了花哨的游标代码,只需使用std::tuple<>进行此测试

在我的机器上,对于各种数据大小,元组循环的速度始终是原始指针版本的两倍。

我的系统配置是Windows 8上带有发布版本的Visual C ++ 2013 x64。我确实尝试在Visual Studio中启用各种优化,例如 内联函数扩展:任何合适的(/ Ob2) 但它似乎没有改变我案件的时间结果。

我确实需要做两件额外的事情来避免VS的积极优化 1)我强制将测试数据数组分配到堆上,而不是堆栈上。当我计时时,这可能是由于内存缓存效应造成了很大的不同 2)我通过在结尾处写入静态变量来强制产生副作用,因此编译器不会跳过我的循环。

struct forceHeap
{
    __declspec(noinline) int* newData(int M)
    {
        int* data = new int[M];
        return data;
    }    
};

void timeSumCursor()
{
    static int gIntStore; 
    int maxCount = 20;
    int M = 10000000; 
    // compiler might place array on stack which changes the timing
    // int* data = new int[N];         
    forceHeap fh;
    int* data = fh.newData(M);
    int *front = data; 
    int *end = data + M;

    int j = 0;
    for (int* p = front; p < end; ++p)
    {
        *p = (++j) % 1000;
    }

    {
        BEGIN_TIMING_BLOCK("raw pointer loop", maxCount);
        int* p = front;
        int sum = 0;
        int* cursor = front;
        while (++cursor != end)
        {
            sum += *cursor;
        }
        gIntStore = sum;// force a side effect
        END_TIMING_BLOCK(); 
    }
    printf("%d\n", gIntStore);

    {
        // just use a simple tuple to show the issue 
        // rather full blown cursor object
        BEGIN_TIMING_BLOCK("tuple loop", maxCount);
        int sum = 0;
        auto cursor = std::make_tuple(front);
        while (++std::get<0>(cursor) != end)
        {
            sum += *std::get<0>(cursor);
        }
        gIntStore = sum; // force a side effect
        END_TIMING_BLOCK();
    }
    printf("%d\n", gIntStore);

    delete[] data;
}

0 个答案:

没有答案