我刚刚阅读了博文here并尝试做类似的事情,这是我的代码来检查示例1和2中的内容:
int doSomething(long numLoop,int cacheSize){
long k;
int arr[1000000];
for(k=0;k<numLoop;k++){
int i;
for (i = 0; i < 1000000; i+=cacheSize) arr[i] = arr[i];
}
}
正如博文中所述,doSomething(1000,2)和doSomething(1000,1)的执行时间应该几乎相同,但我分别得到2.1s和4.3s。谁能帮我解释一下? 谢谢。
更新1: 我刚刚将数组的大小增加到100倍
int doSomething(long numLoop,int cacheSize){
long k;
int * buffer;
buffer = (int*) malloc (100000000 * sizeof(int));
for(k=0;k<numLoop;k++){
int i;
for (i = 0; i < 100000000; i+=cacheSize) buffer[i] = buffer[i];
}
}
不幸的是,doSomething(10,2)和doSomething(10,1)的执行时间仍然大不相同:3.02s和5.65s。任何人都可以在你的机器上测试吗?
答案 0 :(得分:2)
使用doSomething(1000,2),当你使用doSomething(1000,1)时,你正在做一半内在循环。
你的内部循环由cacheSize递增,所以值为2只给你一半的值迭代。数组的大小约为4MB,这是典型的虚拟内存页面大小。
实际上我有点惊讶的是,好的编译器只是没有优化这个循环,因为没有变量。这可能是问题的一部分。
答案 1 :(得分:2)
您的阵列大小为4M还不够大。整个数组适合缓存(并在第一个k
循环后位于缓存中),因此时序由指令执行决定。如果你使arr
远大于缓存大小,你将开始看到预期的效果。
(当你使arr
大于缓存时,你会看到一个额外的效果:运行时应该以{{1}}大小线性增加,直到你超过缓存,当你看到一个膝盖的性能和它会突然变得更糟,运行时间会以新的线性标度增加)
编辑:我尝试了第二个版本并进行了以下更改:
arr
以确保volatile int *buffer
未被优化。buffer[i] = buffer[i]
进行编译,以确保循环得到充分优化,以防止循环开销占主导地位。当我尝试时,我几乎完全相同:
-O2
在这里你可以看到使步幅两个完整的高速缓存行的效果:
kronos /tmp $ time ./dos 2
./dos 2 1.65s user 0.29s system 99% cpu 1.947 total
kronos /tmp $ time ./dos 1
./dos 1 1.68s user 0.25s system 99% cpu 1.926 total