我正在进行身体模拟,我有一个存储粒子加速度的数组。现在我正在尝试并行化我的代码,我遇到了这个问题,因为数组类型是真的,我无法锁定它。因为OpenMP中的init_lock
子例程,参数必须是整数。
有办法解决吗?我使用了关键构造,但它对计算时间没有影响。在这里,我尝试锁定数组索引,但它也没有工作。
call omp_init_lock(i,j)
!$omp parallel
!$omp do private(rx,ry,rz,rsqd,r2i,r6i,virij,ff,i,j) schedule(dynamic)
do i=1,m-1
do j=i+1,m
rsqd = 0.0
rx = x(i,1) - x(j,1)
ry = x(i,2) - x(j,2)
rz = x(i,3) - x(j,3)
rsqd = rsqd + rx*rx +ry*ry + rz*rz
!calculation of another variable ff
! $omp critical
call omp_set_lock(i)
a(i,1) = a(i,1) + rx*ff
a(i,2) = a(i,2) + ry*ff
a(i,3) = a(i,3) + rz*ff
call omp_unset_lock(i)
call omp_set_lock(j)
a(j,1) = a(j,1) - rx*ff
a(j,2) = a(j,2) - ry*ff
a(j,3) = a(j,3) - rz*ff
call omp_unset_lock(j)
! $omp end critical
end do
end do
答案 0 :(得分:0)
一个选项是在a(i,x)
和a(j,x)
语句周围使用一个关键部分,并消除所有锁(它们被冗余使用)。
所以我建议你这样做:
!$omp parallel
!$omp do private(rx,ry,rz,rsqd,r2i,r6i,virij,ff,i,j) schedule(dynamic)
do i=1,m-1
do j=i+1,m
rsqd = 0.0
rx = x(i,1) - x(j,1)
ry = x(i,2) - x(j,2)
rz = x(i,3) - x(j,3)
rsqd = rsqd + rx*rx +ry*ry + rz*rz
!calculation of another variable ff
! $omp critical
a(i,1) = a(i,1) + rx*ff
a(i,2) = a(i,2) + ry*ff
a(i,3) = a(i,3) + rz*ff
a(j,1) = a(j,1) - rx*ff
a(j,2) = a(j,2) - ry*ff
a(j,3) = a(j,3) - rz*ff
! $omp end critical
end do
end do
答案 1 :(得分:0)
您发现的锁是数据结构,只允许一个线程在定义的代码中执行代码。如果您想保护矩阵的每个单元格上的访问权限,您可以为整个矩阵进行单一锁定,保护每个单元格或两者之间的某些内容,例如保护每行/列的访问权限。
我建议你将omp atomic
构造用于你拥有的每个关键任务。与omp critical
和锁相比,原子的好处是原子可以由编译器/运行时通过原子处理器指令实现,从而提高性能,因为它们减少了单个处理器执行的指令量(参见{ {3}}和openMP, atomic vs critical?)。使用omp atomic
构造的另一个好处是,在编译时未启用OpenMP代码时,代码会无缝编译,如果使用锁定则不是这样。
这可能是您的代码的变体:
!$omp parallel
!$omp do private(rx,ry,rz,rsqd,r2i,r6i,virij,ff,i,j) schedule(dynamic)
do i=1,m-1
do j=i+1,m
rsqd = 0.0
rx = x(i,1) - x(j,1)
ry = x(i,2) - x(j,2)
rz = x(i,3) - x(j,3)
rsqd = rsqd + rx*rx +ry*ry + rz*rz
!calculation of another variable ff
!$omp atomic
a(i,1) = a(i,1) + rx*ff
!$omp atomic
a(i,2) = a(i,2) + ry*ff
!$omp atomic
a(i,3) = a(i,3) + rz*ff
!$omp atomic
a(j,1) = a(j,1) - rx*ff
!$omp atomic
a(j,2) = a(j,2) - ry*ff
!$omp atomic
a(j,3) = a(j,3) - rz*ff
end do
end do
编辑由于您有兴趣从此获得进一步的表现,我建议您使用一些性能分析工具(例如Vtune [1],Paraver [2], TAU [3],Scalasca [4]甚至gprof)。话虽如此,在并行化此代码时提到的小影响可能表明此循环代表总执行运行时的一小部分。性能分析工具可帮助您确定哪些是最耗时的例程。
如果这部分代码具有代表性,则可能会发生创建并行区域并等待它和/或由于关键/原子区域导致的序列化的成本可能会限制您获得的加速。对于第一个,您可以考虑为dynamic
计划提供最小块(例如dynamic, 4
)。这将有助于i
接近m
的最后一次迭代,因此do j
循环不会代表大量的工作。您还可以考虑guided
日程安排。它的行为在某种程度上与dynamic
类似,但迭代次数(块)动态减少 - 即
[1] http://openmp.org/forum/viewtopic.php?f=3&t=1549
[2] https://software.intel.com/en-us/intel-vtune-amplifier-xe
[3] http://www.bsc.es/computer-sciences/performance-tools/paraver