在这样的场景中你会如何避免虚假分享?

时间:2013-10-13 18:08:32

标签: c arrays openmp false-sharing

在下面的代码中,我使用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)但是我注意到仍有一个区域确实落后 - 我在上面标注的最里面的循环。

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

 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 for循环,因为我依赖于为每次迭代计算的d_equ。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

的东西
cells