0

在下面的代码中,我使用 OpenMP 的标准parallel for子句进行了并行化。

#pragma omp parallel for private(i, j, k, d_equ) shared(cells, tmp_cells, params)
for(i=0; i<some_large_value; i++)
{
   for(j=0; j<some_large_value; j++)
   {
       ....
       // Some operations performed over here which are using private variables
       ....

       // Accessing a shared array is causing False Sharing
       for(k=0; k<10; k++)
       {
          cells[i * width + j].speeds[k] = some_calculation(i, j, k, cells);
       }
   }
}

这让我的运行时间有了显着改善(~140s 到 ~40s),但我注意到仍然有一个领域确实落后了——我在上面标记的最里面的循环。

我肯定知道上面的数组会导致错误共享,因为如果我在下面进行更改,我会看到性能的另一个巨大飞跃(约 40 秒到约 13 秒)。

 for(k=0; k<10; k++)
 {
     double somevalue = some_calculation(i, j);
 }

换句话说,只要我将内存位置更改为写入私有变量,就会有巨大的加速提升。

在我刚刚解释的场景中,有什么方法可以通过避免错误共享来改善我的运行时间?即使问题本身被提及很多,我似乎也无法在网上找到许多似乎有助于解决此问题的资源。

我有一个想法来创建一个过大的数组(需要的 10 倍),以便在每个元素之间保持足够的边距空间,以确保当它进入缓存行时,没有其他线程会拾取它。然而,这未能产生预期的效果。

是否有任何简单的(或者如果需要的话甚至很难)方法来减少或删除该循环中发现的错误共享?

任何形式的见解或帮助将不胜感激!

编辑:假设 some_calculation() 执行以下操作:

 (tmp_cells[ii*params.nx + jj].speeds[kk] + params.omega * (d_equ[kk] - tmp_cells[ii*params.nx + jj].speeds[kk]));

我无法将此计算移出我的 for 循环,因为我依赖于为每次迭代计算的 d_equ。

4

1 回答 1

1

在回答你的问题之前,我必须问一下,当你使用整体cells作为函数的输入时,真的是一种错误的共享情况some_calcutation()吗?看来您实际上是在共享整个阵列。您可能想提供有关此功能的更多信息。

如果是,请继续以下操作。

您已经证明私有变量double somevalue会提高性能。为什么不直接使用这种方法?

您可以在循环之前定义一个私有数组,而不是使用单个double变量,在循环中计算它们,然后使用类似的东西将其复制回循环之后private_speed[10]for kcells

 memcpy(cells[i*width+j].speed, private_speed, sizeof(...));
于 2013-10-13T18:58:32.277 回答