Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 用于顺序内存访问的编译器嵌套循环优化。_C++_Performance_Gcc_Loops_Compiler Construction - Fatal编程技术网

C++ 用于顺序内存访问的编译器嵌套循环优化。

C++ 用于顺序内存访问的编译器嵌套循环优化。,c++,performance,gcc,loops,compiler-construction,C++,Performance,Gcc,Loops,Compiler Construction,我在matrix乘法基准测试中遇到了一个奇怪的性能问题(matrix_mult在Metis中来自套件)。对基准测试进行了优化,以平铺数据,从而使活动工作集为12kb(3个32x32整数的平铺),并适合一级缓存。长话短说,在某些阵列输入大小(40968192)上,交换内部两个most循环的性能差异几乎是4倍,而在其他阵列输入大小上的性能差异约为30%。问题本质上归结为按顺序访问元素,而不是按步幅模式访问元素。我认为某些数组大小造成了错误的跨步访问,从而产生了大量缓存线冲突。从双向关联L1更改为8向

我在matrix乘法基准测试中遇到了一个奇怪的性能问题(matrix_mult在Metis中来自套件)。对基准测试进行了优化,以平铺数据,从而使活动工作集为12kb(3个32x32整数的平铺),并适合一级缓存。长话短说,在某些阵列输入大小(40968192)上,交换内部两个most循环的性能差异几乎是4倍,而在其他阵列输入大小上的性能差异约为30%。问题本质上归结为按顺序访问元素,而不是按步幅模式访问元素。我认为某些数组大小造成了错误的跨步访问,从而产生了大量缓存线冲突。从双向关联L1更改为8向关联L1时,性能差异明显减小

我的问题是为什么gcc不优化循环顺序以最大化顺序内存访问

下面是该问题的简化版本(请注意,性能时间高度依赖于L1配置。下面所示的数字来自2.3 GHZ AMD系统,64K L1双向关联编译为-O3)

N=ARRAY\u SIZE//1024
int*mat_A=(int*)malloc(N*N*sizeof(int));
int*mat_B=(int*)malloc(N*N*sizeof(int));
int*mat_C=(int*)malloc(N*N*sizeof(int));
//mat_B元素以长度为N的步幅模式访问
//这需要800毫秒
对于(int t=0;t<1000;t++)
对于(int a=0;a<32;a++)
对于(int b=0;b<32;b++)
对于(int c=0;c<32;c++)
mat_C[N*a+b]+=mat_a[N*a+C]*mat_b[N*C+b];
//内部两个循环交换
//元素现在在内部循环中按顺序访问
//这需要172毫秒
对于(int t=0;t<1000;t++)
对于(int a=0;a<32;a++)
对于(int c=0;c<32;c++)
对于(int b=0;b<32;b++)
mat_C[N*a+b]+=mat_a[N*a+C]*mat_b[N*C+b];
  • gcc可能无法证明指针不重叠。如果可以使用非标准扩展,可以尝试使用
  • gcc没有充分利用您的体系结构来避免为每个处理器重新编译的必要性。为您的系统使用具有适当值的选项可能会有所帮助

  • gcc有一系列的优化,只是做你想要的

    查找-floop strip mine和-floop block编译器选项

    引自手册:

    对循环执行循环阻塞转换。封闭露天矿 循环中的每个循环嵌套,以便 元素循环适合缓存内部。条带长度可通过以下方式更改: 循环块平铺大小参数


    因为很难向编译器证明这样的更改不会改变操作的语义。也许您会对google gcc+graphite感兴趣,它是基于多面体模型的循环转换的一个合并分支。在某个地方有一个可能的转换列表。我认为,由于整数加法是可交换的,因此对于编译器来说,证明该操作对循环器顺序是不变的是相当简单的。我想知道代码示例是什么使得优化变得不平凡。值得注意的是,限制是C99的标准,而不是C++。另请参见@torek,我知道,只是想说明它是一个非标准的扩展,但受到许多编译器的支持。谢谢,虽然问题不是由于缓存中不适合内部循环,因为优化已经在代码中手动完成。内部循环只有12kb的数据占用空间。3*1024个整数值。
    N = ARRAY_SIZE // 1024
    int* mat_A = (int*)malloc(N*N*sizeof(int));
    int* mat_B = (int*)malloc(N*N*sizeof(int));
    int* mat_C = (int*)malloc(N*N*sizeof(int));
    
    // Elements of mat_B are accessed in a stride pattern of length N
    // This takes 800 msec  
    for (int t = 0; t < 1000; t++) 
       for (int a = 0; a < 32; a++) 
          for (int b = 0; b < 32; b++)
             for (int c = 0; c < 32; c++) 
                mat_C[N*a+b] += mat_A[N*a+c] * mat_B[N*c+b];
    
    // Inner two loops are swapped
    // Elements are now accessed sequentially in inner loop
    // This takes 172 msec  
    for (int t = 0; t < 1000; t++) 
       for (int a = 0; a < 32; a++) 
          for (int c = 0; c < 32; c++) 
             for (int b = 0; b < 32; b++)
                mat_C[N*a+b] += mat_A[N*a+c] * mat_B[N*c+b];