[Directive] do/for

알고리즘을 작성하면서, 가장 많이 쓰는 기능중 하나가 반복문 입니다. 반복문에 대해서 병렬화 작업을 해주는 OpenMP Directive는 do/for 입니다. Fortran 에서는 Do이고, C/C++에서는 for Directive 입니다. [Directive] do 를 이용하여서, 1에서 10까지의 덧셈을 병렬로 실행하는 포트란 코드는 다음과 같습니다.

[Fortran 90]
! omp_parallel.f90
! compile with: /openmp
   
    program Console
    implicit none
    !Variables
    parameter NUM_THREADS = 4
    parameter NUM_START = 1
    parameter NUM_END = 10
    integer :: i, nRet, nSum, nStart, nEnd
    integer :: nThreads, nTmp
    integer :: uTmp
    integer :: nSumCalc
    integer :: omp_get_num_threads
   
    nRet = 0
    nSum = 0
    nStart = NUM_START
    nEnd = NUM_END
    nThreads = 0
    nTmp = nStart + nEnd
    uTmp = (abs(nStart - nEnd) + 1) * abs(nTmp) / 2
    nSumCalc = uTmp
   
    if (nTmp < 0) then
        nSumCalc = -nSumCalc
    end if
   
    call omp_set_num_threads(NUM_THREADS)
   
    !$omp parallel default(none) private(i) shared(nSum, nThreads, nStart, nEnd)
    !$omp master
    nThreads = omp_get_num_threads()
    !$omp end master
   
    !$omp do
    do i=nStart, nEnd
        !$omp atomic
        nSum = nSum + i
    end do
    !$omp end do
    !$omp end parallel
    if (nThreads == NUM_THREADS) then
        write(*,"(I1, A26)") NUM_THREADS, " OpenMP threads were used."
    else
        write(*, "(A9, I1, A21, I1, A11)"), "Expected ", NUM_THREADS,&
            " OpenMP threads, but ", nThreads, " were used."
        nRet = 1
    end if
   
    if (nSum /= nSumCalc) then
        write(*, "(A11, I2, A8, I2, A11, I2, A6, I2, A14)"), &
            "The sum of ", NUM_START, " through ", NUM_END, " should be ",&
            nSumCalc, " but ", nSum, " was reported!"
        nRet = 1
    else
        write(*, "(A11, I2, A8, I2, A4, I2)"), "The sum of ", NUM_START,&
            " through ", NUM_END," is ", nSum
    end if

    end program Console

[Output]
4 OpenMP threads were used.
The sum of  1 through10 is 55

위 코드에서 parallel 은 쓰레딩을 실행하는 directive이고, master 는 뒤에 오는 블럭을 하나의 쓰레드로 실행 시켜주는 directive 입니다. 다른 쓰레드들을 다음 블럭에 있는 것을 바로 수행합니다. [directive] do 는 블럭사이에 있는 반복문을 병렬화하여서 수행하도록 합니다. 마지막으로 [directive] atomic 이 있는데, 블락사이에 있는 명령문이 실행되는 동안 공유되고 있는 변수들에 대해서 보호해주는 역할을 합니다. nSum + 1이 수행되는 동안 다른 쓰레드가 nSum을 업데이트 시키면 틀린 값이 나오므로 atomic으로 업데이트하지 못하도록 보호해 주어야 합니다. atomic 은 간단한 연산에 대해서만 작동하는데, 조금 더 복잡한 명령문에는 critical 을 이용하여 보호 할 수 있습니다. 하지만 일반적으로 속도는 atomic 이 critical보다 빠릅니다. 아래는 do/for 가 지원하는 Clause 목록입니다.

The for directive supports the following OpenMP clauses:

출처 - https://msdn.microsoft.com/en-us/library/6z19s8e0.aspx

댓글

이 블로그의 인기 게시물

[Linux, AIX] 사용자 계정 생성 및 설정

[AIX] rpm 설치와 rpm 으로 패키지 설치 및 삭제

Ubuntu 에서 Fortran 시작하기