你会如何避免这种情况下的虚假共享?

问题描述:

在下面的代码中,我已经使用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至40岁〜),但仍然有一个领域我已经真正注意到滞后 - 最里面的循环我上面标注。

我知道确实上述数组正在导致虚假共享,因为如果我在下面进行更改,我会看到性能上的另一个巨大飞跃(〜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])); 

,因为我靠,这是每次迭代计算d_equ我动不了这个计算出来的我的for循环。

在回答你的问题之前,我不禁要问,当你使用整个cells作为函数some_calcutation()的输入时,是否真的是虚假的共享情况?看来你是分享整个阵列actrually。您可能想要提供有关此功能的更多信息。

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

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

不要使用单个double可变的,你可以只在for k循环之前定义的私人阵列private_speed[10],在循环计算它们,并与东西环路像

memcpy(cells[i*width+j].speed, private_speed, sizeof(...)); 
+0

如何回来后把它复制到cells我到底会在循环之后复制一个私有变量?我会更新我的代码以显示确切的计算结果。我使用'some_calculation'函数作为占位符来隐藏不需要的实现细节。 –

+1

类似于'memcpy(cells [i * width + j] .speed,private_speed,sizeof(...))'应该没问题。 – kangshiyin

+0

我刚刚尝试过你的memcpy想法,但它并没有改变速度。虽然在理论上应该是这样的,应该发生更少的虚假共享,单元阵列本身仍然被更新,这会导致其他内核使它们具有的任何缓存副本无效。 –