5

我为拉普拉斯方程(一个简单的热板问题)添加了 OpenACC 指令到我的红黑 Gauss-Seidel 求解器中,但是 GPU 加速的代码并不比 CPU 快,即使对于大问题也是如此。

我还编写了一个 CUDA 版本,这比两者都快得多(对于 512x512,大约 2 秒,而 CPU 和 OpenACC 为 25 秒)。

谁能想到造成这种差异的原因?我意识到 CUDA 提供了最有潜力的速度,但 OpenACC 应该比 CPU 提供更好的解决更大问题的东西(比如 Jacobi 求解器,用于解决此处演示的同类问题)。

这是相关代码(完整的工作源代码在这里):

#pragma acc data copyin(aP[0:size], aW[0:size], aE[0:size], aS[0:size], aN[0:size], b[0:size]) copy(temp_red[0:size_temp], temp_black[0:size_temp])
// red-black Gauss-Seidel with SOR iteration loop
for (iter = 1; iter <= it_max; ++iter) {
  Real norm_L2 = 0.0;

  // update red cells
  #pragma omp parallel for shared(aP, aW, aE, aS, aN, temp_black, temp_red) \
      reduction(+:norm_L2)
  #pragma acc kernels present(aP[0:size], aW[0:size], aE[0:size], aS[0:size], aN[0:size], b[0:size], temp_red[0:size_temp], temp_black[0:size_temp])
  #pragma acc loop independent gang vector(4)
  for (int col = 1; col < NUM + 1; ++col) {
    #pragma acc loop independent gang vector(64)
    for (int row = 1; row < (NUM / 2) + 1; ++row) {

      int ind_red = col * ((NUM / 2) + 2) + row;        // local (red) index
      int ind = 2 * row - (col % 2) - 1 + NUM * (col - 1);  // global index

      #pragma acc cache(aP[ind], b[ind], aW[ind], aE[ind], aS[ind], aN[ind])

      Real res = b[ind] + (aW[ind] * temp_black[row + (col - 1) * ((NUM / 2) + 2)]
                         + aE[ind] * temp_black[row + (col + 1) * ((NUM / 2) + 2)]
                         + aS[ind] * temp_black[row - (col % 2) + col * ((NUM / 2) + 2)]
                         + aN[ind] * temp_black[row + ((col + 1) % 2) + col * ((NUM / 2) + 2)]);

      Real temp_old = temp_red[ind_red];
      temp_red[ind_red] = temp_old * (1.0 - omega) + omega * (res / aP[ind]);

      // calculate residual
      res = temp_red[ind_red] - temp_old;
      norm_L2 += (res * res);

    } // end for row
  } // end for col

  // update black cells
  #pragma omp parallel for shared(aP, aW, aE, aS, aN, temp_black, temp_red) \
          reduction(+:norm_L2)
  #pragma acc kernels present(aP[0:size], aW[0:size], aE[0:size], aS[0:size], aN[0:size], b[0:size], temp_red[0:size_temp], temp_black[0:size_temp])
  #pragma acc loop independent gang vector(4)
  for (int col = 1; col < NUM + 1; ++col) {
    #pragma acc loop independent gang vector(64)
    for (int row = 1; row < (NUM / 2) + 1; ++row) {

      int ind_black = col * ((NUM / 2) + 2) + row;      // local (black) index
      int ind = 2 * row - ((col + 1) % 2) - 1 + NUM * (col - 1);    // global index

      #pragma acc cache(aP[ind], b[ind], aW[ind], aE[ind], aS[ind], aN[ind])

      Real res = b[ind] + (aW[ind] * temp_red[row + (col - 1) * ((NUM / 2) + 2)]
                         + aE[ind] * temp_red[row + (col + 1) * ((NUM / 2) + 2)]
                         + aS[ind] * temp_red[row - ((col + 1) % 2) + col * ((NUM / 2) + 2)]
                         + aN[ind] * temp_red[row + (col % 2) + col * ((NUM / 2) + 2)]);

      Real temp_old = temp_black[ind_black];
      temp_black[ind_black] = temp_old * (1.0 - omega) + omega * (res / aP[ind]);

      // calculate residual
      res = temp_black[ind_black] - temp_old;       
      norm_L2 += (res * res);

    } // end for row
  } // end for col

  // calculate residual
  norm_L2 = sqrt(norm_L2 / ((Real)size));

  if(iter % 100 == 0) printf("%5d, %0.6f\n", iter, norm_L2);

  // if tolerance has been reached, end SOR iterations
  if (norm_L2 < tol) {
    break;
  }
}
4

2 回答 2

3

好吧,我找到了一个半解决方案,可以显着减少较小问题的时间。

如果我插入以下行:

acc_init(acc_device_nvidia);
acc_set_device_num(0, acc_device_nvidia);

在我开始计时器之前,为了激活和设置 GPU,512x512 问题的时间下降到 9.8 秒,1024x1024 下降到 42 秒。增加问题规模进一步表明,即使是 OpenACC 也可以与在四个 CPU 内核上运行相比有多快。

有了这个改变,OpenACC 代码比 CUDA 代码慢了大约 2 倍,随着问题规模越来越大,差距越来越接近一点点(~1.2)。

于 2012-10-19T20:04:59.250 回答
0

我下载了您的完整代码并编译并运行它!没有停止运行和指导

if(iter % 100 == 0) printf("%5d, %0.6f\n", iter, norm_L2);

结果是:

100、楠

200,楠

……

我将所有Real类型 的变量更改为float类型 ,结果是:

100, 0.000654

200, 0.000370

……,……

……,……

8800, 0.000002

8900, 0.000002

9000, 0.000001

9100, 0.000001

9200, 0.000001

9300, 0.000001

9400, 0.000001

9500, 0.000001

9600, 0.000001

9700, 0.000001

中央处理器

迭代次数:9796

总时间:5.594017 秒

NUM = 1024 结果是:

迭代次数:27271

总时间:25.949905 秒

于 2012-11-25T10:38:39.370 回答