【问题标题】:Openmp array reductions with Fortran使用 Fortran 减少 Openmp 数组
【发布时间】:2014-09-12 23:32:55
【问题描述】:

我正在尝试并行化我编写的代码。我在对数组执行缩减时遇到问题。这对于小型数组似乎一切正常,但是当数组大小超过某个点时,我要么得到堆栈溢出错误,要么崩溃。

我尝试在编译时使用 /F 增加堆栈大小,我在 Windows 上使用 ifort,我还尝试将 set KMP_STACKSIZE=xxx 传递给英特尔特定的堆栈大小减免。这有时会有所帮助并允许代码在我的循环中进一步前进,但最终并不能解决问题,即使堆栈大小为 1Gb 或更大。

下面是我的代码的一个独立的小型工作示例。它以串行方式工作,并且使用一个线程。或者有很多线程,但有一个小的“N”。较大的 N(即示例中的 250,000)会导致问题。

我不认为这些数组如此庞大以至于会导致重大问题,并且假设增加我的堆栈空间会有所帮助 - 还有其他选择,还是我在编码中遗漏了一些重要的东西?

program testreduction
    use omp_lib
    implicit none
    integer :: i, j, nthreads, Nsize
    integer iseed /3/
    REAL, allocatable :: A(:,:), B(:), C(:), posi(:,:)
    REAL :: dx, dy, r, Axi, Ayi, m, F
    !Set size of matrix, and main loop
    Nsize = 250000
    m = 1.0
    F = 1.0
    !Allocate posi array
    allocate(posi(2,Nsize))
    !Fill with random numbers
    do i=1,Nsize
        do j=1,2
            posi(j,i) = (ran(iseed))
        end do
    end do
    !Allocate other arrays
    allocate(A(2,Nsize), C(Nsize), B(Nsize))

    print*, sizeof(A)+sizeof(B)+sizeof(C)
    !$OMP parallel
    nthreads = omp_get_num_threads()
    !$OMP end parallel

    print*, "Number of threads ", nthreads
    !Go through each array and do some work, calculating a reduction on A, B and C.
    !$OMP parallel do schedule(static) private(i, j, dx, dy, r, Axi, Ayi) reduction(+:C, B, A)
    do i=1,Nsize
        do j=1,Nsize
            !print*, i
            dx = posi(1,i) - posi(1,j)
            dy = posi(2,i) - posi(2,j)
            r = sqrt(dx**2+dy**2)
            Axi = -m*(F)*(dx/(r))
            Ayi = -m*(F)*(dy/(r))
            A(1,i) = A(1,i) + Axi
            A(2,i) = A(2,i) + Ayi
            B(i) = B(i) + (Axi+Ayi)
            C(i) = C(i) + dx/(r) + dy/(r)
        end do    
    END DO
    !$OMP END parallel do

end program

更新

我所说的更好的例子..

program testreduction2
    use omp_lib
    implicit none
    integer :: i, j, nthreads, Nsize, q, k, nsize2
    REAL, allocatable :: A(:,:), B(:), C(:)
    integer, ALLOCATABLE :: PAIRI(:), PAIRJ(:)

    Nsize = 25
    Nsize2 = 19
    q=0

    allocate(A(2,Nsize), C(Nsize), B(Nsize))
    ALLOCATE(PAIRI(nsize*nsize2), PAIRJ(nsize*nsize2))

    do i=1,nsize
        do j =1,nsize2
            q=q+1
            PAIRI(q) = i
            PAIRJ(q) = j
        end do
    end do

    A = 0
    B = 0
    C = 0

    !$OMP parallel do schedule(static) private(i, j, k)
    do k=1,q
        i=PAIRI(k)
        j=PAIRJ(k)
        A(1,i) = A(1,i) + 1
        A(2,i) = A(2,i) + 1
        B(i) = B(i) + 1
        C(i) = C(i) + 1
    END DO
    !$OMP END parallel do

    PRINT*, A
    PRINT*, B
    PRINT*, C       
END PROGRAM

【问题讨论】:

    标签: arrays fortran openmp fortran90 reduction


    【解决方案1】:

    问题是您正在减少非常大的数组。请注意,其他语言(C、C++)在 OpenMP 4.5 之前无法减少数组。

    但是我看不出你的情况有什么减少的理由,你只更新每个元素一次。

    试试吧

    !$OMP parallel do schedule(static) private(i, dx, dy, r, Axi, Ayi)
    do i=1,Nsize
      do j=1,Nsize
        ...
        A(1,i) = A(1,i) + Axi
        A(2,i) = A(2,i) + Ayi
        B(i) = B(i) + (Axi+Ayi)
        C(i) = C(i) + dx/(r) + dy/(r)
      end do
    end do
    !$OMP END parallel do
    

    关键是线程不会相互干扰。每个线程使用不同的is 集合,因此ABC 的元素也不同。

    即使你想出了一个看起来很有必要的案例,你也可以随时重写它来避免它。您甚至可以自己分配一些缓冲区并模拟减少。或者使用原子更新。

    【讨论】:

    • 在这个例子中你是对的,我不需要减少,但是在我的真实代码中。这只是我能想到的最简单的例子,但同样失败了。
    • 您的更新仍然不需要减少。如果您有不同的东西,请展示它。
    • 还是太简单了,PAIRI 只依赖于i 而你不使用j。没必要减。显示实际代码。
    • 也许我没有得到这个,但是如果两个线程都具有相同的 i 值并尝试写入同一个元素,这不是问题吗?
    • 奇怪,所有大数组都是可分配的。将它们列在缩减子句中不应导致堆栈空间耗尽,因为私有副本也应该是可分配的。
    猜你喜欢
    • 2013-12-23
    • 2017-03-22
    • 1970-01-01
    • 2021-04-27
    • 2012-06-04
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 2015-09-09
    相关资源
    最近更新 更多