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

5. 유도데이터타입(CONTIGUOUS), 예제로 배우기

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

MPI 튜토리얼을 제공하는 원본게시글을 따라가며 이해한 내용들을 기록한 문서이다.

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

 

V MPI 유도데이터타입 _____________________

- Derived Data Type.

 

    코딩을 하다보면, 데이터를 읽어 올때 내장 된 데이터 타입 외의 데이터 구조를 사용하면 편한 경우가 있다. 예를 들어 1~100을 1~10, 10 단위로 나눠야하는 상황(1~10, ... , 91~100)을 생각해 보자. 이런경우 루프를 통해 정수를 하나씩 읽어오기에는 다소 비효율적이다. 그보다 정수 10개짜리 리스트 형식을 정의해 한번에 10개씩 읽어오면 코드는 훨씬 간결하해지고 가독성이 좋아질 수 있다.

    데이터 구조를 지정해주는 기법이 MPI 표준에도 존재한다. MPI 기본 데이터 유형을 기반으로 고유 한 데이터 구조를 정의 할 수있는 기능이다. 아에 데이터 구조를 만든다기보다, 기 존재하는 유형을 바탕으로 하기 때문에 파생 데이터 형식이라 부른다. 이러한 유도데이터 타입으로는 기본적으로 Contiguous, Vector, Indexed, 그리고 Struct이 존재한다.

 

˙MPI_TYPE_CONTIGUOUS : 가장 간단한 기법으로 기 존재하는 데이터 유형이 반복되어있는 형식을 정의한다.

˙MPI_TYPE_VECTOR (hvector) : contiguous와 비슷하나, 데이터간 일정한 간격(hvector는 간격이 바이드 단위)을 둔다. 

˙MPI_TYPE_INDEXED (hindexed) : 데이터의 시작지점(offset) 및 블록의 길이(blocklens)을 지정하여 데이터를 읽어온다. 

˙MPI_TYPE_STRUCT  (MPI_Type_create_struct in MPI-3.0) : 한번에 여러 데이터 형식을 지정할 수 있다.

 

    당연히 위 짧은 설명과 코드의 파라미터만 봐서는 이해하기 어려우니, 예제를 통해서 알아보자. 

 

 

V.1 MPI_TYPE_CONTIGUOUS _________________________________

 

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

 

  program contiguous

  include 'mpif.h'
  integer SIZE
  parameter(SIZE=4)
  integer numtasks, rank, source, dest, tag, i, ierr
  real*4 a(0:SIZE-1,0:SIZE-1), b(0:SIZE-1)
  integer stat(MPI_STATUS_SIZE)
  integer columntype ! required variable

  tag = 1

  ! Fortran stores this array in column major order
  data a /1.0, 2.0, 3.0, 4.0, &
          5.0, 6.0, 7.0, 8.0, &
          9.0, 10.0, 11.0, 12.0, &
          13.0, 14.0, 15.0, 16.0 /

  call MPI_INIT(ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
  call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)

  ! create contiguous derived data type
  call MPI_TYPE_CONTIGUOUS(SIZE, MPI_REAL, columntype, ierr)
  call MPI_TYPE_COMMIT(columntype, ierr)
  if (numtasks .eq. SIZE) then

    ! task 0 sends one element of columntype to all tasks
    if (rank .eq. 0) then
      do i=0, numtasks-1
          call MPI_SEND(a(0,i), 1, columntype, i, tag, MPI_COMM_WORLD,ierr)
      end do
    endif

    ! all tasks receive columntype data from task 0
    source = 0
    call MPI_RECV(b, SIZE, MPI_REAL, source, tag, MPI_COMM_WORLD, stat, ierr)
    print *, 'rank= ',rank,' b= ',b
  else
    print *, 'Must specify',SIZE,' processors. Terminating.'
  endif

  ! free datatype when done using it
  call MPI_TYPE_FREE(columntype, ierr)
  call MPI_FINALIZE(ierr)

  end

 

    그대로 컴파일하고 수행을 하였을때, 결과가 나오지 않는 체 멈추는 현상이 발견되었다. 무한루프가 돌 일도 없는데 말이다. 디버깅을 좀 해봤더니, 마스터 프로세서(0)에서 MPI_SEND를 마스터 프로세서로 보낼 시 멈춰 있었다. 블로킹 통신이라그런지 SEND에 걸리고 RECV도 같은 버퍼를 찾으려하는 등진행하지 못하고 멈춰 있던 것이다. 하지만 정확한 요인을 잘 모르겠다...공부해야지

    어쨋든 같은 결과 값을 내기 위해서 다음과 같이 수정하였다.

 

       program contiguous
       
       include 'mpif.h'
       integer SIZE
       parameter(SIZE=4)
       integer numtasks, rank, source, dest, tag, i, ierr
       real*4 a(0:SIZE-1,0:SIZE-1), b(0:SIZE-1)
       integer stat(MPI_STATUS_SIZE)
       integer columntype ! required variable
       tag = 1
       
       ! Fortran stores this array in column major order
       data a /1.0, 2.0, 3.0, 4.0, &
               5.0, 6.0, 7.0, 8.0, &
               9.0, 10.0, 11.0, 12.0, &
               13.0, 14.0, 15.0, 16.0 /
               
       call MPI_INIT(ierr)
       call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
       call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr)
       
       ! create contiguous derived data type
       call MPI_TYPE_CONTIGUOUS(SIZE, MPI_REAL, columntype, ierr)
       call MPI_TYPE_COMMIT(columntype, ierr)
       
       if (numtasks .eq. SIZE) then
         ! task 0 sends one element of columntype to all tasks
         if (rank .eq. 0) then
           do i=1, numtasks-1
               call MPI_SEND(a(0,i), 1, columntype, i, tag, &
                             MPI_COMM_WORLD,ierr)
           end do
           print *, 'rank= ', rank, ' b= ', a(0:3,0)
         else
             ! all tasks receive columntype data from task 0
           source = 0
           call MPI_RECV(b, SIZE, MPI_REAL, source, tag,&
                         MPI_COMM_WORLD,stat, ierr)
           print *, 'rank= ',rank,' b= ',b
         endif
         
       else
       
         print *, 'Must specify',SIZE,' processors. Terminating.'
         
       endif
       
       ! free datatype when done using it
       call MPI_TYPE_FREE(columntype, ierr)
       call MPI_FINALIZE(ierr)
       
       end

 

결과적으로 이쁜 출력을 보여줬다. 

 

$ mpirun -n 4 ./contiguous_ex.exe
 rank=            0  b=    1.0000000       2.0000000       3.0000000       4.0000000
 rank=            1  b=    5.0000000       6.0000000       7.0000000       8.0000000
 rank=            3  b=    13.000000       14.000000       15.000000       16.000000
 rank=            2  b=    9.0000000       10.000000       11.000000       12.000000

 

본 포스팅에서는 가장 간단한 기법인 MPI_TYPE_CONTIGUOUS 만 다뤘다. 추가적으로 Vector, Indexed, 그리고 Struct에 대해서도 다루도록 하겠다.

 

 

 

반응형

댓글