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

2024-02-13

我在矩阵乘法基准测试中遇到了一个奇怪的性能问题(Metis 中的 matrix_mult)MOSBENCH http://pdos.csail.mit.edu/mosbench/套房)。基准测试经过优化,可平铺数据,使活动工作集大小为 12kb(3 个 32x32 整数的平铺),并且适合 L1 缓存。长话短说,交换最里面的两个循环在某些数组输入大小(4096、8192)上的性能差异几乎为 4 倍,而在其他数组输入大小上大约有 30% 的差异。问题本质上归结为按顺序访问元素而不是以跨步模式访问元素。我认为某些数组大小会产生错误的跨步访问,从而产生大量缓存行冲突。从 2 路关联 L1 更改为 8 路关联 L1 时,性能差异明显较小。

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

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

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

  1. gcc 可能无法证明指针不重叠。如果您可以使用非标准扩展,您可以尝试使用__限制 http://gcc.gnu.org/onlinedocs/gcc/Restricted-Pointers.html.
  2. gcc 没有充分利用您的体系结构来避免为每个处理器重新编译的必要性。使用选项-march http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options为您的系统设置适当的值可能会有所帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用于顺序内存访问的编译器嵌套循环优化。 的相关文章

随机推荐