我遇到了非常奇怪的性能问题,与访问内存有关。 代码段是:
#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
速度也高于简单分配 阅读和写入内存有什么不同吗?为什么我会有如此奇怪的表现?
提前致谢!
答案 0 :(得分:6)
你的假设确实是错误的......
答案 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已过时,但仍然非常擅长解释一般概念。