【问题标题】:linux c++: test of the cacheline size performance effect not as expectedlinux c++:测试cacheline size性能效果不如预期
【发布时间】:2017-09-19 10:25:21
【问题描述】:

据说对于普通的x86 cpu(i7 mac),cpu cacheline大小是64bytes,所以如果使用数组大小​​

下面是我的程序:

#include<sys/time.h>
#include<stdlib.h>
#include<stdio.h>
size_t cacheline=16;
int main(int argc,char*argv[]){
    size_t loopCount=2000000000;
    if(argc==2){loopCount=atol(argv[1]);}
    printf("loop=%ld\n",loopCount);
    int array[cacheline];
    for(size_t a=0;a<cacheline;++a){
        array[a]=a;
    }
    size_t c=0;
    long sum=1;
    for(size_t i=0;i<loopCount;++i){
        if(c==cacheline)c=0;
        sum+=array[c++];//
    }
    printf("sum=%ld\n",sum);
    return 0;
}

clang++ test07_cacheline.cpp -O2 -o test07_cacheline && time ./test07_cacheline 2000000000
loop=2000000000
sum=63354543092609

real    0m2.810s
user    0m2.794s
sys 0m0.009s

但在我的测试程序中我发现,无论我将“数组”的大小设置为16、64、256还是65536,时间执行时间基本相同。理论或我的程序设计有什么问题?我还尝试了一些来自互联网的其他程序,结果相同,如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
long timediff(clock_t t1,clock_t t2){
    return (t2-t1)*1000/CLOCKS_PER_SEC;
}
int main(int argc,char*argv[]){
    int array_size=65536;
    if(argc>=2)array_size=atoi(argv[1]);
    int repeat_times=2000000000;
    long array[array_size];
    for(int i=0;i<array_size;++i){
        array[i]=i;
    }
    int j=0;
    int k=0;
    int c=0;
    clock_t start=clock();
    while(j++<repeat_times){
        if(k==array_size){k=0;}
        c+=array[k++];
    }
    clock_t end=clock();
    printf("c=%d,%lu\n",c,timediff(start,end));
    return 0;
}

g++ test08_cacheline.cpp -O2 -o test08_cacheline && ./test08_cacheline
c=1865233920,2800

不管array_size如何位。那么关于缓存线如何影响我的程序性能的任何解释?

【问题讨论】:

  • 只是为了确保:您是否在启用优化的情况下进行编译?另外,你是如何在你的第一个程序中测量时间的?我没有看到任何计时代码,如果您将程序作为一个整体进行测量,您的结果可能会因您对 printf 等的调用而被抛出。
  • 您显示的代码似乎在 c 中,但您已用 c++ 标记了这个问题。请相应地编辑标签。
  • 我将标签更改为 c。我用 -O2 编译,只是我的编辑。谢谢。

标签: c linux performance caching size


【解决方案1】:

您缺少的是两次执行都利用数据局部性

您正在从一个连续的数组中读取数据。您的缓存将读取阵列的连续块。唯一的区别在于加载块的次数。

这个数字没有那么大,而且,编译器有能力预测何时加载一个新块,特别是如果你标记了一些优化规则,比如向量化。

更多信息请阅读here

如果您想了解性能如何变化,请尝试以这种方式修改您的代码:

   while(j++<repeat_times){
        if(k==array_size){k=0;}
        int position = ((c+k)*j)%array_size;
        c+=array[position];
        k++;
    }

这样你会失去数据的局部性。


更新

性能更多地取决于内存访问模式而不是缓存大小。更准确地说,如果程序主要是顺序的,缓存大小不是什么大问题。如果有相当多的随机访问,缓存大小真的很重要。

如果您想尝试查看缓存大小如何导致不同的性能,您可以尝试:

  1. 删除执行随机访问的数据局部性
  2. 然后更改数组的大小。

这样,如果每次随机访问时数组的大小都适合您的缓存,则该块将已经进入缓存。

注意你不是唯一一个在你的电脑上使用缓存的人!

【讨论】:

  • 谢谢,我知道这种“丢失数据局部性”会影响性能,但我希望看到的是检查缓存行大小将如何影响性能,并尝试使用纯 c 程序(没有 gcc扩展)通过实验找出缓存线大小(64)的数量。我怎样才能做到这一点?
  • 我测试将“cacheline”从 16 设置为 65536,结果相同。我希望当它是 65536 时,应该会发生更多的“缓存无效”,因此会更慢?
  • @Troskyvs 您是否使用随机访问进行测试?你能分享你的代码吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
相关资源
最近更新 更多