2014-07-22 4 views
0

필자가 작성한 코드를 병렬 처리하려고합니다. 배열에 감축을 수행하는 데 문제가 있습니다. 모든 작은 배열에 대해 잘 작동하는 것, 그러나 배열 크기가 특정 지점 위에 갈 때 나는 스택 오버플로 오류 또는 충돌 얻을.Fortran에서 Openmp 배열 축소

컴파일 시간에/F를 사용하여 스택 크기를 늘리려고했는데, Windows에서 ifort를 사용하고 있고, set KMP_STACKSIZE = xxx 인텔 전용 스택 크기 decleration을 전달하려고했습니다. 이것은 때로는 도움이되고 코드가 더 이상 루프를 통해 진행될 수 있지만 결국 스택 크기가 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 

UPDATE

내가 무슨 말을 좀 더 예 ..

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 

답변

2

문제는 당신이 정말로 큰 배열을 감소한다는 것이다. 다른 언어 (C, C++)에서는 배열을 전혀 줄일 수 없습니다.

그러나 귀하의 사례가 감소한 이유는 없지만 각 요소는 한 번만 업데이트됩니다.

!$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 

점은 스레드가 interfare하지 않는 것입니다보십시오. 모든 스레드는 i의 다른 집합을 사용하므로 A, BC의 다른 요소가 사용됩니다.

필요하다고 생각되는 경우가 생기더라도이를 피하기 위해 언제든지 다시 작성할 수 있습니다. 버퍼를 직접 할당하고 줄일 수 있습니다. 또는 원자 적 업데이트를 사용하십시오.

+0

이 예제에서 당신은 정확하지만 나는 실제 코드에서는 감소가 필요하지 않습니다. 이것은 제가 생각할 수있는 가장 단순한 예일뿐입니다. – MechanicalEagle36

+0

업데이트가 줄어들 필요가 없습니다. 다른 것을 가지고 있다면 보여주십시오. –

+0

다른 코드 예제를 추가했습니다. 실제로이 코드 예제를 실제로 보여줍니다. 이 경우, 나는 ** 어떤 일이 발생했는지를 알기 위해 감축을하지 않았습니다 **. 각 배열의 각 요소에 대한 대답은 19 여야합니다. 이상하게도 위의 예에서 실제로 작동하는 것 같습니다. 나는 왜 그런지 잘 모르겠다. 이 예제에서 'i'와 같은 값을 갖는 다른 스레드를 중지시키는 것은 무엇이며 왜이 문제가 발생하지 않습니까? – MechanicalEagle36