이 글은 블로킹과 논블로킹에 대한 이해를 바탕으로 논블로킹 통신(Nonbloking communications)의 예제를 다뤘다.
MPI 코드로 수치적분을 구현한 원본게시글을 따라가며 이해한 내용들을 기록한 문서이다.
포트란으로 병렬컴퓨팅 배우기 ←링크
II. MPI 집합통신과 수치적분
- Numerical Integration wtih MPI Collective Communications.
MPI 집합통신 예제로 평범하고 하찮은(원본이 이렇게 소개한다.) 그리고 간단한 알고리즘인 수치적분법을 가져왔다. 부분적분을 각 프로세서에서 진행하고, 그 합을 다시 마스터 프로세서에서 수행하는 것으로 적분이 완료되는 알고리즘이다. 코드만 보고 알고리즘 이해가 어렵다면, 앞 포스트의 수치적분 개념설명(링크)을 참고하길 바란다.
위 그림과 함께 예제를 간단히 소개하겠다. P0 ~ P3 은 프로세서로써 각각 노란 박스안을 적분할 것이다. 그리고 그 로컬(local)적분값을 P0(마스터프로세서)로 송신해 최종 적분 값을 도출해낸다. 여기서 사용된 기법은 중앙점(Midpoint) 적분으로, 적분과정에서 사각형의 넓이들의 덧샘만 존재한다. 따라서 병렬 프로그램으로 작성하기 수월하다.
II.2 포트란 + MPI 코드
C 코드도 원본 포스팅에 함께 첨부되어있으니, C 사용자라면 참고하길 바란다.
Program Example1_3
c#######################################################################
c# #
c# This is an MPI example on parallel integration to demonstrate the #
c# use of: #
c# #
c# * MPI_Init, MPI_Comm_rank, MPI_Comm_size, MPI_Finalize #
c# * MPI_Recv, MPI_Isend, MPI_Wait #
C# * MPI_ANY_SOURCE, MPI_ANY_TAG #
c# #
c# Dr. Kadin Tseng #
c# Scientific Computing and Visualization #
c# Boston University #
c# 1998 #
c# #
c#######################################################################
implicit none
integer n, p, i, j, proc, ierr, master, myid, tag, comm, request
real h, a, b, integral, pi, ai, my_int, integral_sum
include "mpif.h" ! brings in pre-defined MPI constants, ...
integer status(MPI_STATUS_SIZE) ! size defined in mpif.h
data master/0/ ! processor 0 collects integral sums from other processors
comm = MPI_COMM_WORLD
call MPI_Init(ierr) ! MPI 활성화
call MPI_Comm_rank(comm, myid, ierr) ! 현 프로세서 ID 번호
call MPI_Comm_size(comm, p, ierr) ! 총 프로세서 개수
pi = acos(-1.0) ! = 3.14159...
a = 0.0 ! 하한
b = pi/2. ! 상한
n = 500 ! 한 구간 당 간격 개수
tag = 123 ! 로컬합계 송수신 테그
h = (b-a)/n/p ! 한 간격의 길이
ai = a + myid*n*h ! 구간의 하한 (*한 프로세서안에서, 여기로부터 500개의 간격 계산)
my_int = integral(ai, h, n)
write(*,*)'myid=',myid,', my_int=',my_int
if(myid .eq. master) then ! the following is serial
integral_sum = my_int
do proc=1,p-1
call MPI_Recv(
& my_int, 1, MPI_REAL,
& MPI_ANY_SOURCE, ! message source
& MPI_ANY_TAG, ! message tag
& comm, status, ierr) ! status identifies source, tag
integral_sum = integral_sum + my_int
enddo
write(*,*)'The Integral =', integral_sum ! sum of my_int
else
call MPI_Isend(
& my_int, 1, MPI_REAL, ! buffer, size, datatype
& master, tag, ! destination and tag
& comm, request, ierr) ! get handle for MPI_Wait to check status
call other_work(myid)
! 블로킹커뮤니케이션이면 MPI_Recv가 완료될때까지 다음작동을 하지않는데, 논블로킹인지라 이 함수를 호출하는것.
call MPI_Wait(request, status, ierr) ! 블로킹처럼 만들기 위해 일단 Wait.
endif
call MPI_Finalize(ierr)
end
subroutine other_work(myid)
implicit none
integer myid
write(*,"('more work on process ',i3)") myid
return
end
real function integral(ai, h, n)
implicit none
integer n, j
real h, ai, aij
integral = 0.0 ! initialize integral
do j=0,n-1 ! sum integrals
aij = ai +(j+0.5)*h ! abscissa mid-point
integral = integral + cos(aij)*h
enddo
return
end
여기서 MPI_ANY_SOURCE 와 MPI_ANY_TAG는 눈여겨볼만하다. 먼저 수신이 준비된 메시지들먼저 받는 역할을 한다. 메시지 수신 시 프로세스 번호를 정해줘, 이미 수신대기 중인 메시지를 무시해버리는 경우를 방지하기 위함이다. 어떤 프로세서의 메시지를 받는지는 MPI_Recv 의 반환값에 포함되어 나오므로 크게 걱정하지 않아도 된다(ex, status(MPI_SOURCE)). 여기서 테그 값은 mpif.h에 초기지정된 wild card 값이 사용되는데, 이또한 status(MPI_TAG) 로 알아볼 수 있다.
어쨋든 코드를 살펴보았다면 이제 컴파일을 하고,
$mpif90 ex_3.for -o ex_3.exe
모델을 구동시켜 본다.
$mpiexec -np 4 ex_3.exe
II.3 구동결과
myid= 3 , my_int= 7.61204883E-02
myid= 0 , my_int= 0.38268363
myid= 2 , my_int= 0.21677256
myid= 1 , my_int= 0.32442346
more work on process 2
more work on process 3
more work on process 1
The Integral = 1.0000001
결과를 살펴보자. 마스터 프로세서에서 전체 합이 다 구해지기 전에 more work on process # 가 있는 것을 확인할 수 있다. 물론 블로킹이 되지 않은 후속 작업이 마스터 프로세서에 보내지는 행위와 상관있다면, 오류가 뜰 가능성이 높다. 이런 점을 잘 고려하여 non-blocking을 적절히 섞어주면 효율적인 계산이 가능할 것이다.
'Engineer > 병렬컴퓨팅' 카테고리의 다른 글
5. 유도데이터타입(CONTIGUOUS), 예제로 배우기 (0) | 2020.03.24 |
---|---|
4. 집합통신-2, 예제(수치적분)로 배우기 (0) | 2020.03.24 |
3. 집합통신, 예제(수치적분)로 배우기 (0) | 2020.03.24 |
1. 블로킹 통신, 예제(수치적분)로 배우기 (2) | 2020.03.19 |
포트란으로 MPI 배우기 (0) | 2020.03.19 |
댓글