处理连续块与非连续内存块时的效率

时间:2013-11-26 11:48:46

标签: c++

我有一个结构

struct A
{
int v[10000000];
};

如果我有A a[2];并希望计算这两种方法中哪一种最快的值总和?

int method_1(const A &a[],int length)
{
int total = 0;
for(int i=0;i<length;i++)
for(int j=0;j<10000000;j++)
total+=a[i][j];

return total;
}


int method_2(const A &a[],int length)
{
int total = 0;
for(int j=0;j<10000000;j++)
for(int i=0;i<length;i++)
total+=a[i][j];

return total;
}

a [2]被声明为结构A的两个连续块,如下所示:

---- a [0] ---- / --- a [1] ----

[] [] [] [] [] [] [] [] / [] [] [] [] [] [] [] []

所以,我可能会试图说method_1更快,基于直觉是块是连续的,并且每个块的v的迭代也是连续的。

我真正感兴趣的是如何真正访问内存以及访问内存的最有效方式。

编辑

我已将v的尺寸从32更改为10000000,因为显然我不明白我指的是一般情况

4 个答案:

答案 0 :(得分:2)

每次读取内存片段时,整个缓存行将从主内存读取到CPU缓存,今天你可能有一个32字节长的缓存行。主要是因为这个读取连续的内存块很快。

现在有超过一个缓存行...

在你的情况下,两种情况都可能有相似的性能,因为两个数组很可能不会碰撞到同一个缓存行,所以两者都可能在不同行的缓存中,所以我怀疑性能会相似。

在这种情况下,你可以考虑改变性能的一个相关的事情是不使用[]运算符,而是使用像这样的“迭代器”迭代更多:

int method_1(const A &a[],int length)
{
    int total = 0;
    for(const A* aIt=a;aIt<a+length;++aIt)
        for(const v* vIt=aIt->v;vIt<aIt->v+10000000;++vIt)
            total+=*vIt;

    return total;
}

这样你就避免了double [],它只是乘以数组元素的sizeof(可能是优化但可能没有,如果不是,那么当调用数百万次时它会很昂贵)。您的编译器可能足够聪明以优化代码,就像我已经证明只使用添加但...它很可能不是,并且我已经看到这对于每个元素执行的操作是有很大不同的像增量一样微不足道 - 你最好衡量这一点,看看这些选项如何在你的环境中发挥作用。

答案 1 :(得分:1)

按照它们在内存中出现的顺序访问元素将提高大多数案例的性能,因为它允许预取程序在您使用之前加载数据。此外,如果您以不连续的方式使用数据,您可能会多次加载和丢弃相同的缓存行,这会产生成本。

答案 2 :(得分:0)

数据大小足够小,可以完全适合现代CPU上的单个缓存行。我不确定是否通过编译器

来转换此代码

答案 3 :(得分:0)

我认为method_2不比method_1慢。内存块将被带到CPU主存储器,然后访问[0]和[1]两者将占用相同的时间。

对于更安全的一面,method_1总是被认为比method_2更好。