我刚刚读了一篇博文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.1秒和4.3秒。有人能帮我解释一下吗?谢谢。
更新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.02秒和5.65秒。任何人都可以在你的机器上进行测试吗?
发布于 2012-09-27 09:16:34
您的4M数组大小不够大。整个数组都适合高速缓存(并且在第一个k循环之后位于高速缓存中),因此定时由指令执行控制。如果您将arr设置得比缓存大小大得多,您将开始看到预期的效果。
(当你使arr大于缓存时,你会看到一个额外的效果:运行时应该随着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在这里,您可以看到将步幅设置为两条完整缓存线的效果:
kronos /tmp $ time ./dos 16
./dos 16 1.65s user 0.28s system 99% cpu 1.926 total
kronos /tmp $ time ./dos 32
./dos 32 1.06s user 0.30s system 99% cpu 1.356 total发布于 2012-09-27 09:06:39
在使用doSomething(1000,2)时,执行内部循环的次数是使用doSomething(1000,1)时的一半。
内部循环的增量为cacheSize,因此值为2的迭代次数仅为值为1的迭代次数的一半。数组大小约为4MB,这是典型的虚拟内存页面大小。
实际上,我有点惊讶,一个好的编译器不会优化这个循环,因为没有变量的改变。这可能是问题的一部分。
https://stackoverflow.com/questions/12612536
复制相似问题