0

我在 R 中有一个程序,它调用了几个支持 openMP 的 Fortran 例程。有两个 Fortran 例程sub_1sub_2. 第一个在 R 函数中被调用两次,而第二个被调用一次。除了一些小事情外,这两个例程几乎相同。我调用第一个例程,然后调用第二个例程,然后再次调用第一个例程。但是,如果我让它们都启用了 openMP,则该函数在第二次使用第一个 fortran 例程时停止执行任何操作(没有错误或停止执行,只是坐在那里)。

如果我禁用 openMP,sub_1那么一切运行正常。如果我改为禁用 .openMP 中的 openMP sub_2,那么它在sub_1. 这很奇怪,因为它显然可以很好地通过第一次使用。

我认为这可能与线程未正确关闭或其他原因有关(我对 openMP 不太了解)。然而,另一个奇怪的是,调用这三个例程的 R 函数被调用了四次,如果我只启用 openMP in sub_2,那么这工作正常(即第二个、第三个等调用sub_2不会挂起)。我只是不知道它为什么会这样做!作为参考,这是以下代码sub_1

subroutine correlation_dd_rad(s_bins,min_s,end_s,n,pos1,dd,r)   
!!! INTENT IN !!!!!!!!
integer             :: s_bins       !Number of separation bins
integer             :: N            !Number of objects
real(8)             :: pos1(3,N)    !Cartesian Positions of particles
real(8)             :: min_s        !The smallest separation calculated.
real(8)             :: end_s        !The largest separation calculated.
real(8)             :: r(N)         !The radii of each particle (ascending)
!!! INTENT OUT !!!!!!!
real(8)             :: dd(N,s_bins)         !The binned data.

!!! LOCAL !!!!!!!!!!!!
integer             :: i,j      !Iterators
integer             :: bin
real(8)             :: d            !Distance between particles.
real(8)             :: dr,mins,ends
real(8),parameter   :: pi = 3.14159653589

integer             :: counter
dd(:,:) = 0.d0

dr = (end_s-min_s)/s_bins

!Perform the separation binning
mins = min_s**2
ends = end_s**2

counter = 1000
!$OMP parallel do private(d,bin,j)
do i=1,N
    !$omp critical (count_it)
        counter = counter - 1
    !$omp end critical (count_it)
    if(counter==0)then
        counter = 1000
        write(*,*) "Another Thousand"
    end if
    do j=i+1,N
        if(r(j)-r(i) .GT. end_s)then
            exit
        end if

        d=(pos1(1,j)-pos1(1,i))**2+&
            &(pos1(2,j)-pos1(2,i))**2+&
            &(pos1(3,j)-pos1(3,i))**2
        if(d.LT.ends .AND. d.GT.mins)then
            d = Sqrt(d)
            bin = Floor((d-min_s)/dr)+1
            dd(i,bin) = dd(i,bin)+1.d0
            dd(j,bin) = dd(j,bin)+1.d0
        end if
    end do
end do
!$OMP end parallel do
write(*,*) "done"
end subroutine

有谁知道为什么会发生这种情况?

干杯。

我将添加一个我能想到的最小的例子,它确实重现了这个问题(顺便说一下,这一定是一个 R 问题——我在这里展示的类型的一个小例子,但是用 fortran 编写的可以正常工作)。所以我在fortran中有上面的代码和下面的代码,编译到共享对象correlate.so

subroutine correlation_dr_rad(s_bins,min_s,end_s,n,pos1,n2,pos2,dd,r1,r2)

!!! INTENT IN !!!!!!!!
integer             :: s_bins       !Number of separation bins
integer             :: N            !Number of objects
integer             :: n2
real(8)             :: pos1(3,N)    !Cartesian Positions of particles
real(8)             :: pos2(3,n2)   !random particles
real(8)             :: end_s        !The largest separation calculated.
real(8)             :: min_s        !The smallest separation
real(8)             :: r1(N),r2(N2) !The radii of particles (ascending)

!!! INTENT OUT !!!!!!!
real(8)             :: dd(N,s_bins)         !The binned data.

!!! LOCAL !!!!!!!!!!!!
integer             :: i,j      !Iterators
integer             :: bin
real(8)             :: d            !Distance between particles.
real(8)             :: dr,mins,ends
real(8),parameter   :: pi = 3.14159653589

integer             :: counter
dd(:,:) = 0.d0

dr = (end_s-min_s)/s_bins

!Perform the separation binning

mins = min_s**2
ends = end_s**2

write(*,*) "Got just before parallel dr"
counter = 1000
!$OMP parallel do private(d,bin,j)
do i=1,N
    !$OMP critical (count)
            counter = counter - 1
        !$OMP end critical (count)
            if(counter==0)then
                write(*,*) "Another thousand"
                counter = 1000
            end if
    do j=1,N2


        if(r2(j)-r1(i) .GT. end_s)then
            exit
        end if
        d=(pos1(1,j)-pos2(1,i))**2+&
            &(pos1(2,j)-pos2(2,i))**2+&
            &(pos1(3,j)-pos2(3,i))**2
        if(d.GT.mins .AND. d.LT.ends)then
            d = Sqrt(d)
            bin = Floor((d-min_s)/dr)+1
            dd(i,bin) = dd(i,bin)+1.d0
        end if
    end do
end do
!$OMP end parallel do

write(*,*) "Done"
end subroutine

然后在 R 中,我有以下函数——前两个只是包装了上面的 fortran 代码。第三个以与我的实际代码类似的方式调用它:

correlate_dd_rad = function(pos,r,min_r,end_r,bins){
  #A wrapper for the fortran routine of the same name.
  dyn.load('correlate.so')
  out = .Fortran('correlation_dd_rad',
             s_bins = as.integer(bins),
             min_s = as.double(min_r),
             end_s = as.double(end_r),
             n = as.integer(length(r)),
             pos = as.double(t(pos)),
             dd = matrix(0,length(r),bins), #The output matrix.
             r = as.double(r))

  dyn.unload('correlate.so')
  return(out$dd)
}

correlate_dr_rad = function(pos1,r1,pos2,r2,min_r,end_r,bins){
  #A wrapper for the fortran routine of the same name
  N = length(r1)
  N2 = length(r2)
  dyn.load('correlate.so')

  out = .Fortran('correlation_dr_rad',
             s_bins = as.integer(bins),
             min_s = as.double(min_r),
             end_s = as.double(end_r),
             n = N,
             pos1 = as.double(t(pos1)),
             n2 = N2,
             pos2 = as.double(t(pos2)),
             dr = matrix(0,nrow=N,ncol=bins),
             r1 = as.double(r1),
             r2 = as.double(r2))

  dyn.unload('correlate.so')
  return(out$dr)
}

the_calculation = function(){

  #Generate some data to use
  pos1 = matrix(rnorm(30000),10000,3)
  pos2 = matrix(rnorm(30000),10000,3)

  #Find the radii
  r1 = sqrt(pos1[,1]^2 + pos1[,2]^2+pos1[,3]^2)
  r2 = sqrt(pos2[,1]^2 + pos2[,2]^2+pos2[,3]^2)

  #usually sort them but it doesn't matter here.

  #Now call the functions
  print("Calculating the data-data pairs")
  dd = correlate_dd_rad(pos=pos1,r=r1,min_r=0.001,end_r=0.8,bins=15)

  print("Calculating the data-random pairs")
  dr = correlate_dr_rad(pos1,r1,pos2,r2,min_r=0.001,end_r=0.8,bins=15)

  print("Calculating the random-random pairs")
  rr = correlate_dd_rad(pos=pos2,r=r2,min_r=0.001,end_r=0.8,bins=15)

  #Now we would do something with it but I don't care in this example.
  print("Done")
}

运行这个我得到输出:

 [1] "Calculating the data-data pairs"
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  Another Thousand
  done
 [1] "Calculating the data-random pairs"
  Got just before parallel dr
  Another thousand
  Another thousand

然后它就坐在那里......实际上,运行它几次表明它每次都会改变它挂起的位置。有时它会在第二次调用 to 时获得大部分时间,而在correlate_dd_rad其他情况下它只会在调用 to 中途获得correlate_dr_rad

4

1 回答 1

1

我不确定这是否会解决您的问题,但这确实是一个错误。在子程序correlation_dd_rad中,当您打算关闭并行区域时,您实际上添加了注释。为了更清楚地显示以下内容:

 !OMP end parallel do

应转换为:

 !$OMP end parallel do

作为旁注:

  1. use omp_lib如果您不调用库函数,则不需要
  2. 您可以使用atomic构造(参见最新 OpenMP 规范的第 2.8.5 节)以原子方式访问特定存储位置,而不是critical构造
  3. 总是给critical结构起一个名字(规范的第 2.8.2 节)

所有没有名称的关键构造都被认为具有相同的未指定名称。

于 2012-09-24T20:37:16.277 回答