为什么内存访问速度如此之慢?

时间:2012-01-18 23:13:55

标签: c++ arrays performance memory vector

我遇到了非常奇怪的性能问题,与访问内存有关。 代码段是:

#include <vector>
using namespace std;

vector<int> arrx(M,-1); 
vector< vector<int> > arr(N,arrx);

...
for(i=0;i<N;i++){
  for(j=0;j<M;j++){
    //>>>>>>>>>>>> Part 1 <<<<<<<<<<<<<<
    // Simple arithmetic operations
    int n1 = 1 + 2;  // does not matter what (actually more complicated)
    // Integer assignment, without access to array
    int n2 = n1;

    //>>>>>>>>>>>> Part 2 <<<<<<<<<<<<<<
    // This turns out to be most expensive part
    arr[i][j] = n1;
  }
}

N和M - 是1000 - 10000左右的一些常量。 当我编译此代码(发布版本)时,如果第2部分被评论,则需要大约15个时钟来完成它。使用这部分,执行时间可达100多个时钟,因此几乎慢了10倍。我期望赋值操作比简单的算术运算便宜得多。如果我们不使用数组,这实际上是正确的。但是使用该阵列,分配似乎要贵得多。 我也尝试过1-D阵列而不是2-D - 相同的结果(对于2D显然更慢)。 我还使用int **或int *而不是vector&lt;矢量&lt; int&gt; &GT;或矢量&lt; int&gt; - 结果再次相同。

为什么我在数组赋值方面表现不佳,我可以修复它吗?

编辑: 还有一个观察:如果我们从

更改赋值,则在给定代码的第2部分中
arr[i][j] = n1;  // 172 clocks

n1 = arr[i][j];  // 16 clocks

速度(评论中的数字)上升。更有趣的是,如果我们更改这一行:

arr[i][j] = n1; // 172 clocks

arr[i][j] = arr[i][j] * arr[i][j]; // 110 clocks

速度也高于简单分配 阅读和写入内存有什么不同吗?为什么我会有如此奇怪的表现?

提前致谢!

5 个答案:

答案 0 :(得分:6)

你的假设确实是错误的......

  1. 写入主内存比进行简单添加要慢得多。
  2. 如果你不写,那就是 可能会完全优化循环。

答案 1 :(得分:5)

除非你的实际“第1部分”比你的例子要复杂得多,否则我们就不会感到惊讶了 - 与基本算术相比,内存访问 缓慢。此外,如果您正在使用优化进行编译,那么“第1部分”的大部分或全部可能会被优化掉,因为结果从未使用过。

答案 2 :(得分:2)

你发现了一个关于现代计算机的悲惨事实:与算术相比,内存访问非常慢。你无能为力。这是因为铜线中的电场仅以光速的三分之二左右传播。

答案 3 :(得分:2)

您的嵌套数组将位于50-500MB内存区域。编写那么多内存需要时间,而且没有多少聪明的硬件内存缓存可以帮助那么多。此外,即使单个存储器写入也需要时间,因为它必须通过电路板上的一些铜线到达一段距离的硅块;物理胜利。

但是如果你想深入了解,请尝试使用cachegrind工具(假设它存在于你的平台上)。请注意,您上面使用的代码并不能真正实现大量优化;它的数据访问模式没有大量的重用潜力。

答案 4 :(得分:2)

让我们做一个简单的估计。现在典型的CPU时钟速度约为1--2GHz(千兆= 10到9)。简化(非常)很棒,这意味着单个处理器操作大约需要1ns(纳米= 10,功率为负9)。像int添加这样的简单算法需要几个CPU周期,即十阶。

现在,内存:典型的内存访问时间约为50ns(同样,现在还没有必要进入血腥细节,这是很多)。

你会发现即使在最好的情况下,内存也比CPU慢约5到10倍。

事实上,我在地毯上扫描了大量的细节,但我希望基本的想法是清楚的。如果你有兴趣,有书籍(关键字:缓存,缓存未命中,数据位置等)。 This one已过时,但仍然非常擅长解释一般概念。