본문 바로가기
Engineer/병렬컴퓨팅

3. 집합통신, 예제(수치적분)로 배우기

by _제이빈_ 2020. 3. 24.

이 글은 점대점 통신(블로킹과 논블로킹)에 대한 이해를 바탕으로 집합 통신(Collective communication)의 예제를 다뤘다.

MPI 코드로 수치적분을 구현한 원본게시글을 따라가며 이해한 내용들을 기록한 문서이다.

포트란으로 병렬컴퓨팅 배우기  ←링크

 

III MPI 집합통신과 수치적분

- Numerical Integration wtih MPI Collective Communications.

 

    MPI 집합통신 예제로 평범하고 하찮은(원본이 이렇게 소개한다.) 그리고 간단한 알고리즘인 수치적분법을 가져왔다. 부분적분을 각 프로세서에서 진행하고, 그 합을 다시 마스터 프로세서에서 수행하는 것으로 적분이 완료되는 알고리즘이다. 코드만 보고 알고리즘 이해가 어렵다면, 앞 포스트의 수치적분 개념설명(링크)을 참고하길 바란다.

 

위 그림과 함께 예제를 간단히 소개하겠다. P0 ~ P3 은 프로세서로써 각각 노란 박스안을 적분할 것이다. 그리고 그 로컬(local)적분값을 P0(마스터프로세서)로 송신해 최종 적분 값을 도출해낸다. 여기서 사용된 기법은 중앙점(Midpoint) 적분으로, 적분과정에서 사각형의 넓이들의 덧샘만 존재한다. 따라서 병렬 프로그램으로 작성하기 수월하다.

 

 


 

III.1 집합통신이란?

 

    집합통신(Collective Communications)이란, 프로세서들 간 메세지를 동시에(엄밀하게는 동시는아니다.) 주고 받는 통신을 말한다. 다시말하면, 한 그룹의 프로세서가 참여하는 통신이다. 점대점 통신을 기반으로하나, 그보다 구현이 편리하고 성능이 좋다. 대신, 논블로킹 루틴과 꼬리표(TAG)가 없다.


    집합통신의 종류는 몇가지로 나눌 수 있는데, 오른쪽 그림과 같이 한 프로세서의 하나의 데이터(메시지)를 다른 프로세서들에게 보내는 Broadcast; 한 프로세서의 여러 데이터를 다른 프로세서들에게 하나씩 뿌려주는  Scatter, 그리고 그 반대의 Gather; 프로세서에 각각 분산되어있던 데이터를 모두가 공유하는 All gather; 각자 가진 프로세서의 데이터를 모두에게 뿌려 나눠갖는 All to All 이 있다. 

    메시지 통신과 동시에, 어떤 임의의 계산도 가능하다. Reduce와 Scan을 통해서가능한데, Gather 수행과 동시에 계산을 하는 Reduce; 프로세서 순서별로 하나씩 계산을 더해가며 다시 뿌려주는 Scan이 있다.

 

본 게시글의 예시에는 이 중  Gather 만이 사용되었지만, 많은 예시들이 있으므로 추가적인 게시글을 통해 공유하도록 하겠다.

 

 


 

III.2 포트란 + MPI 코드

 

  언어가 포트란이라 아쉬운 사람은 C 코드도 원본게시글(링크)에 함께 첨부되어있으니 활용하면 좋을 것이다. 

 

      Program Example1_4

      implicit none
      integer n, p, i, j, proc, ierr, master, myid, tag, comm
      real h, a, b, integral, pi, ai, my_int, integral_sum, buf(50) !<- buf to gather messages
      include "mpif.h"  ! brings in pre-defined MPI constants, ...
      data master/0/    ! processor 0 collects integral sums from other processors

      comm = MPI_COMM_WORLD
      call MPI_Init(ierr)                        ! starts MPI
      call MPI_Comm_rank(comm, myid, ierr)      ! get current proc ID
      call MPI_Comm_size(comm, p, ierr)          ! get number of procs

      pi = acos(-1.0)   !  = 3.14159...
      a = 0.0           ! lower limit of integration
      b = pi*1./2.      ! upper limit of integration
      n = 500           ! number of intervals in (b-a)/p
      h = (b-a)/n/p     ! length of increment

      ai = a + myid*n*h ! lower limit of integration for partition myid
      my_int = integral(ai, h, n)
      write(*,"('Process ',i2,' has the partial sum of',f10.6)")
     &          myid,my_int

      call MPI_Gather(
     &     my_int, 1, MPI_REAL,      ! Send buffer, size, data type
     &     buf, 1, MPI_REAL,      ! Receive buffer, size, data type
     &     master,      ! destination process
     &     comm, ierr)
      write(*,"( 'Message of P#',i2,' is sended')") myid

      if(myid .eq. master) then
        integral_sum = 0.0
        do i=1,p
          write(*,"('buffer #',i2,'=',f10.6)") i,buf(i)
          integral_sum = integral_sum + buf(i)
        enddo
        print *,'The Integral =',integral_sum
      endif

      call MPI_Finalize(ierr)                            ! let MPI finish up ...

      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

   

컴파일을 하고, 실행하면 다음과 같이 출력된다! 적분 값이 1.0000001로 출력되어 잘 구동되었음을 알 수 있다.

 

$ mpiexec -n 4 ./Collective.exe
Process  0 has the partial sum of  0.382684
Process  2 has the partial sum of  0.216773
Message of P# 2 is sended
Process  1 has the partial sum of  0.324423
Message of P# 1 is sended
Message of P# 0 is sended
buffer # 1=  0.382684
buffer # 2=  0.324423
buffer # 3=  0.216773
buffer # 4=  0.076120
 The Integral =   1.0000001
Process  3 has the partial sum of  0.076120
Message of P# 3 is sended
반응형

댓글