首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenMP FORTRAN问题与私有化

OpenMP FORTRAN问题与私有化
EN

Stack Overflow用户
提问于 2013-03-15 12:44:41
回答 2查看 2.3K关注 0票数 0

在下面的代码中,当我将变量"aa“作为私有变量传递时,结果会变得很糟糕。代码的发布方式很好,但是当我替换行时

代码语言:javascript
复制
   !$OMP PARALLEL PRIVATE(iii,iter,y,i,yt) SHARED(bb)

使用

代码语言:javascript
复制
   !$OMP PARALLEL PRIVATE(aa,iter,y,i,yt) SHARED(bb)

代码不能正常工作。

代码语言:javascript
复制
     !!!!!!!! module 
      module common
      use iso_fortran_env
      implicit none
      integer,parameter:: dp=real64
      real(dp):: aa,bb

       contains

      subroutine evolve(y,yevl)
      implicit none
      integer(dp),parameter:: id=2
      real(dp),intent(in):: y(id)
      real(dp),intent(out):: yevl(id)
        yevl(1)=y(2)+1.d0-aa*y(1)**2
        yevl(2)=bb*y(1)
      end subroutine evolve

      end module common

      use common
      implicit none
      integer(dp):: iii,iter,i
      integer(dp),parameter:: id=2
      real(dp),allocatable:: y(:),yt(:)
      integer(dp):: OMP_GET_THREAD_NUM, IXD

       allocate(y(id)); allocate(yt(id)); y=0.d0; yt=0.d0; bb=0.3d0
       !$OMP PARALLEL PRIVATE(iii,iter,y,i,yt) SHARED(bb)
         IXD=OMP_GET_THREAD_NUM()
       !$OMP DO
        do iii=1,20000; print*,iii  !! EXPECTED THREADS TO BE OF 5000 ITERATIONS EACH
          aa=1.d0+dfloat(iii-1)*0.4d0/2000.d0
            loop1: do iter=1,10 !! THE INITIAL CONDITION LOOP
               call random_number(y)!! RANDOM INITIALIZATION OF THE VARIABLE
                loop2: do i=1,70000  !! ITERATION OF THE SYSTEM
                    call evolve(y,yt)
                    y=yt
                enddo loop2     !! END OF SYSTEM ITERATION
              write(IXD+1,*)aa,yt  !!! WRITING FILE CORRESPONDING TO EACH THREAD
            enddo loop1 !!INITIAL CONDITION ITERATION DONE
         enddo
        !$OMP ENDDO
        !$OMP END PARALLEL
        end

有什么问题吗?当我从"iii“生成"aa”时工作得很好,但是当我把它作为私有变量传递时就不行了。谢谢您的意见或建议。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-15 14:29:59

您应该仔细分析变量,特别是考虑它们在不同线程上同时具有不同的值,因为这些值必须声明为OMP私有。在您的示例中,两个变量aaiii都必须是OMP私有的。变量iii,因为它是循环中分布在线程上的计数器,而aa是因为它获得了依赖于iii的值。

编辑:由于每个线程都调用evolve子程序本身,并且evolve应该使用aa的线程特定值(我猜),所以您也应该将aa传递给您的子程序,而不是使用模块变量aa

例行公事应如下所示:

代码语言:javascript
复制
subroutine evolve(y, aa, yevl)
  integer(dp),parameter:: id=2
  real(dp),intent(in):: y(id), aa
  real(dp),intent(out):: yevl(id)
    yevl(1)=y(2)+1.d0-aa*y(1)**2
    yevl(2)=bb*y(1)
  end subroutine evolve

你的主程序中有这样的电话:

代码语言:javascript
复制
call evolve(y, aa, yt)
票数 0
EN

Stack Overflow用户

发布于 2013-03-15 16:52:42

aa是一个模块变量。模块变量既可以共享(默认),也可以是threadprivate。OpenMP标准文档中的示例A.32.2f说明,当在构造的动态范围中访问模块变量时,未指定原始变量还是私有线程副本被访问。threadprivate变量的情况并非如此,因为它们总是存储在线程本地存储中,不管是否在并行区域的词法范围内使用。

如果您声明一个模块变量是私有的,然后将它访问到一个子例程中,那么会发生许多情况。最有可能发生的事情取决于编译器对代码所做的分析。一些编译器可能会检测到,模块子例程只在并行区域内调用,因此使aa引用每个线程的私有副本。其他编译器可能决定始终访问原始模块变量。另一方面,如果子例程在调用子例程中内联,那么它可能引用调用上下文中使用的相同的aa (例如,如果aa被声明为private,则为私有版本)。

下面是gfortran如何在默认优化级别处理PRIVATE(iii,aa,iter,y,i,yt)的示例:

代码语言:javascript
复制
; aa is declared as a global symbol in the BSS section
    .globl  __common_MOD_aa
    .bss
    .align 8
    .type   __common_MOD_aa, @object
    .size   __common_MOD_aa, 8
__common_MOD_aa:
    .zero   8

; Here is how evolve accesses aa
    ...
    movsd   __common_MOD_aa(%rip), %xmm2
    ...

; Here is how the assignment to aa is done inside the parallel region
    ...
    movsd   %xmm0, -72(%rbp)
    ...

私有aa作为一个自动变量实现,并存储在线程堆栈中,而evolve则使用模块中的aa值。因此,该操作员:

代码语言:javascript
复制
aa=1.d0+dfloat(iii-1)*0.4d0/2000.d0

只更改线程内的aa值,而evolve则使用并行区域之外的aa的原始值。

在较高的优化级别上,-O3 gfortranevolve内联到并行区域,并且.

代码语言:javascript
复制
...
mulsd   __common_MOD_aa(%rip), %xmm2
...

内联代码还引用模块中aa的全局值,即两个优化级别之间的行为是一致的。

英特尔Fortran的情况也是如此。

正确的方法是将aa声明为threadprivate而不是将其放在private子句中:

代码语言:javascript
复制
module common
use iso_fortran_env
implicit none
integer,parameter:: dp=real64
real(dp):: aa,bb
!$OMP THREADPRIVATE(aa)
...
 !$OMP PARALLEL PRIVATE(iii,iter,y,i,yt) SHARED(bb)
   IXD=OMP_GET_THREAD_NUM()
   !$OMP DO
   do iii=1,20000; print*,iii  !! EXPECTED THREADS TO BE OF 5000 ITERATIONS EACH
     aa=1.d0+dfloat(iii-1)*0.4d0/2000.d0
...

现在,并行区域和evolve都将对aa的每个线程副本使用一个私有的。由于对线程私有变量的访问通常比对普通私有(堆栈)变量的访问慢,因此在64位x86系统上将aa的值作为参数传递给evolve可能更有意义,正如@Bálint所建议的那样。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15432853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档