在C中测量缓存大小和缓存行大小的影响

时间:2012-09-27 00:51:04

标签: c caching

我刚刚阅读了博文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。任何人都可以在你的机器上测试吗?

2 个答案:

答案 0 :(得分:2)

使用doSomething(1000,2),当你使用doSomething(1000,1)时,你正在做一半内在循环。

你的内部循环由cacheSize递增,所以值为2只给你一半的值迭代。数组的大小约为4MB,这是典型的虚拟内存页面大小。

实际上我有点惊讶的是,好的编译器只是没有优化这个循环,因为没有变量。这可能是问题的一部分。

答案 1 :(得分:2)

您的阵列大小为4M还不够大。整个数组适合缓存(并在第一个k循环后位于缓存中),因此时序由指令执行决定。如果你使arr远大于缓存大小,你将开始看到预期的效果。

(当你使arr大于缓存时,你会看到一个额外的效果:运行时应该以{{1​​}}大小线性增加,直到你超过缓存,当你看到一个膝盖的性能和它会突然变得更糟,运行时间会以新的线性标度增加)

编辑:我尝试了第二个版本并进行了以下更改:

  1. 更改为arr以确保volatile int *buffer未被优化。
  2. 使用buffer[i] = buffer[i]进行编译,以确保循环得到充分优化,以防止循环开销占主导地位。
  3. 当我尝试时,我几乎完全相同:

    -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