如何使用OpenMP使用锁数组索引?

时间:2016-09-06 05:52:58

标签: arrays parallel-processing fortran openmp

我正在进行身体模拟,我有一个存储粒子加速度的数组。现在我正在尝试并行化我的代码,我遇到了这个问题,因为数组类型是真的,我无法锁定它。因为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

2 个答案:

答案 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

[4] http://www.cs.uoregon.edu/research/tau/home.php