为什么循环次序效应在矩阵乘法中运行时间?

时间:2015-03-01 21:58:13

标签: c for-loop matrix

我写了一个C程序来计算两个矩阵的乘积。 问题我注意到for循环的顺序确实很重要。例如:

N = 500

  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      for (int k = 0 ; k < N; ++k) {
       C[i*N+j]+=A[i*N+k] * B[k*N+j];
       }
     }
   }

执行时间(秒):1.1531820000

   for (int j = 0; j < N; ++j) {
     for (int k = 0 ; k < N; ++k) {
       for (int i = 0; i < N; ++i) {
       C[i*N+j]+=A[i*N+k] * B[k*N+j];
       }
     }
   }

执行时间(秒):2.6801300000

矩阵声明:

      A=(double*)malloc(sizeof(double)*N*N);
      B=(double*)malloc(sizeof(double)*N*N);
      C=(double*)malloc(sizeof(double)*N*N);

我运行测试5次而不是计算平均值。任何人都知道为什么会这样?

1 个答案:

答案 0 :(得分:4)

使用第二个循环,当你在内循环中增加i时,你会一直进行很多大跳跃,并且在较小程度上k。缓存可能不是很满意。 第一个循环更好,如果你颠倒j和k的顺序,它甚至会更好。

这基本上是data locality的问题。在现代架构上访问主内存非常慢,因此您的CPU将保留最近访问的内存的缓存并尝试预取可能接下来访问的内存。这些缓存非常有效地加速了分组在相同小区域中的访问,或者访问遵循可预测模式的访问。

在这里,我们转变了一种模式,CPU会在内存中大幅跳跃,然后回到一个很好的大部分顺序模式,因此加速。