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

我在矩阵乘法基准测试中遇到了一个奇怪的性能问题(MOSBENCH套件中的Metis中的matrix_mult)。 该基准进行了优化以平铺数据,使得活动工作集为12kb(3个32x32整数的图块)并且适合L1缓存。 长话短说,在某些数组输入大小(4096,8192)中,交换内部最多的两个循环的性能差异几乎为4倍,而其他差异大约为30%。 问题基本上是顺序访问元素,而不是跨步模式。 某些数组大小,我认为创建了一个糟糕的跨步访问,产生了很多缓存线冲突。 当从双向关联L1变为8向关联L1时,性能差异显着较小。

我的问题是为什么不gcc优化循环顺序来最大化顺序存储器访问?

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

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];

  • gcc可能无法证明指针不重叠。 如果您使用非标准扩展可以尝试使用__restrict。
  • gcc没有充分利用你的架构来避免为每个处理器重新编译的必要性。 使用选项-march和系统的适当值可能会有所帮助。

  • 海湾合作委员会有一堆优化,只是做你想做的。

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

    从手册引用:

    在循环中执行循环阻塞转换。 阻挡带开采循环嵌套中的每个循环,使得元素循环的内存访问适合高速缓存内部。 带长度可以使用loop-block-tile-size参数进行更改。

    链接地址: http://www.djcxy.com/p/931.html

    上一篇: compiler nested loop optimization for sequential memory access.

    下一篇: How can I select an element by name with jQuery?