Mpi 병렬 프로그래밍 | C ++의 실용적인 병렬 처리 : Mpi 기본 사항 상위 75개 답변

당신은 주제를 찾고 있습니까 “mpi 병렬 프로그래밍 – C ++의 실용적인 병렬 처리 : MPI 기본 사항“? 다음 카테고리의 웹사이트 https://chewathai27.com/you 에서 귀하의 모든 질문에 답변해 드립니다: https://chewathai27.com/you/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 CoffeeBeforeArch 이(가) 작성한 기사에는 조회수 23,781회 및 좋아요 473개 개의 좋아요가 있습니다.

mpi 병렬 프로그래밍 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 C ++의 실용적인 병렬 처리 : MPI 기본 사항 – mpi 병렬 프로그래밍 주제에 대한 세부정보를 참조하세요

In this video we look at the basics of parallel programming with MPI!
For code samples: http://github.com/coffeebeforearch
For live content: http://twitch.tv/CoffeeBeforeArch

mpi 병렬 프로그래밍 주제에 대한 자세한 내용은 여기를 참조하세요.

MPI를 이용한 병렬 프로그래밍

MPI를 이용한 병렬 프로그래밍 실제. 4. MPI 병렬 프로그램 예제. 부록 : MPI-2. 용어정리/참고자료. 제 1 장 MPI 소개. MPI를 소개하고 MPI를 이해하는데.

+ 더 읽기

Source: ap2.khu.ac.kr

Date Published: 6/16/2021

View: 5220

MPI C/C++ 를 이용한 병렬 프로그래밍

MPI는 C언어, C++ 및 포트란 프로그램 내에서 프로세스 간의 데이터 전달을 정의함으로써, 병렬 프로그래밍을 가능하게 하는 인터페이스입니다. MPI와 …

+ 여기에 자세히 보기

Source: swstar.tistory.com

Date Published: 10/11/2022

View: 6247

MPI를 이용한 병렬 프로그래밍 – K-atoms mobile

MPI(Message Passing Interface)는 병렬 프로그래밍 모델 중 “메시지 패싱” 모델의 표준으로 알려져 있다. MPI에 대해 알아보기에 앞서 메시지 패싱 프로그래밍 모델에 …

+ 여기에 더 보기

Source: k-atoms.ksc.re.kr

Date Published: 9/3/2021

View: 2615

MPI 병렬 프로그래밍

프로그래머가 담당 : 어렵지만 유용성 좋음(Very Flexible) … 메시지 패싱 병렬 프로그래밍을 위해 표준화된 데이터 통 … MPI는 프로세스 기준으로 작업할당.

+ 여기를 클릭

Source: hpcschool.kr

Date Published: 2/9/2021

View: 3545

MPI 병렬 프로그래밍 – YES24

이제는 멀티코어 병렬컴퓨팅 시대이다!슈퍼 컴퓨터 병렬 프로그래밍 매뉴얼이다. 병렬 처리 관련 기능에 어떤 것이 있고, 어떻게 사용하는지에 대한 …

+ 여기를 클릭

Source: www.yes24.com

Date Published: 8/18/2021

View: 5743

MPI Program – 네이버 블로그

2개의 프로세서가 사용자로부터 정수값 n1, n2를 입력받아 n1~n2를 더하는 병렬프로그램을 고려해보자. 각 프로세스는 아래와 같은 작업을 수행하게 된다.

+ 여기에 자세히 보기

Source: m.blog.naver.com

Date Published: 8/11/2022

View: 8328

멀티코어 시대에 꼭 알아야할 MPI 병렬 프로그래밍 – 교보문고

슈퍼컴퓨터에서 병렬프로그래밍을 처리하는 기법을 실습 중심으로 학습할 수 있다. 더보기. 목차. 1 MPI 소개 1.1 MPI의 개요 1.1.1 메시지 패싱(message passing) …

+ 여기에 표시

Source: www.kyobobook.co.kr

Date Published: 6/27/2022

View: 7725

MPI 병렬 프로그래밍 기초 – 노스페라투!

이번에는 “병렬 프로그래밍 이야기”라는 카테고리로 글을 쓰게 되었습니다. … MPI)는 주로 C와 Fortran에서 쓰이는 병렬화 프로그래밍입니다.

+ 여기를 클릭

Source: nofetan.tistory.com

Date Published: 2/12/2022

View: 3991

주제와 관련된 이미지 mpi 병렬 프로그래밍

주제와 관련된 더 많은 사진을 참조하십시오 C ++의 실용적인 병렬 처리 : MPI 기본 사항. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

C ++의 실용적인 병렬 처리 : MPI 기본 사항
C ++의 실용적인 병렬 처리 : MPI 기본 사항

주제에 대한 기사 평가 mpi 병렬 프로그래밍

  • Author: CoffeeBeforeArch
  • Views: 조회수 23,781회
  • Likes: 좋아요 473개
  • Date Published: 2019. 4. 6.
  • Video Url link: https://www.youtube.com/watch?v=a0V8KpLu7EY

MPI C/C++ 를 이용한 병렬 프로그래밍

개요

프로그램이 여러 개의 CPU 코어에서 돌아갈 수 있게 소스 코드를 작성하면, 생산성을 높이는 데 도움이 됩니다. 필요한 연산을 여러 개의 코어들이 나누어서 수행하기 때문에, 프로그램 실행에 소요되는 시간이 줄어드는 효과가 있는 것이죠. CPU에서 구동되는 프로그램을 병렬화 하는데 있어서 MPI (Message Passing Interface)와 OpenMP가 많이 사용되는데요. 이번 포스팅에서는 MPI를 이용한 병렬 프로그래밍에 대해 다뤄볼까 합니다. MPI는 C언어, C++ 및 포트란 프로그램 내에서 프로세스 간의 데이터 전달을 정의함으로써, 병렬 프로그래밍을 가능하게 하는 인터페이스입니다.

MPI와 OpenMP의 가장 큰 차이점 중 하나는 메모리를 공유하는지의 여부가 될 것입니다. OpenMP의 경우 모든 프로세스 또는 스레드 (thread)에서 메모리에 할당된 변수들을 공유하며 접근이 가능합니다. 예를 들어서 정수형 (int) 변수 a를 선언하고 값을 10으로 정했다면, 모든 스레드는 해당 정수형 변수 a의 값을 10으로 인지하게 되죠. 프로그램 중간에 값을 바꾸는 경우에도, 모든 스레드에 똑같이 적용이 됩니다.

반면에 MPI를 이용한 병렬 프로그램에서는 소스코드에서 하나의 변수로 선언된 것일지라도, 각각의 프로세스가 이름만 같은 별도의 변수를 가지며 그 값도 서로 독립적입니다. 서로 다른 프로세스간에 데이터를 주고받기 위해서는 별도의 함수를 호출할 필요가 있죠. 여기에 대해서는 아래에서 더 자세하게 짚어보도록 하겠습니다. 데이터 송수신을 직접 지정해야 하는 번거로움이 있지만, 프로세스들이 동일한 물리적 메모리를 공유할 필요가 없다는 장점이 있습니다. 그래서 여러 개의 노드 (컴퓨터)가 연결된 슈퍼컴퓨터를 사용한다면 MPI가 특히 유용합니다.

반응형

MPI 라이브러리 설치

당연한 얘기지만, MPI를 사용하기 위해서는 라이브러리가 필요한데요. Open MPI와 MPICH가 많이 사용됩니다. 대부분의 슈퍼컴퓨터에서는 MPI 라이브러리들이 미리 설치되어 있어서, 홈 디렉토리에 있는 .bashrc 파일 등을 이용해 로드하기만 하면 됩니다. 설치 및 사용에 있어서 주의할 점이 있다면, Open MPI와 MPICH가 가진 기능들이 상당부분 겹치기 때문에 충돌이 일어날 수 있다는 것입니다. 헤더파일과 라이브러리를 자동으로 탐색하도록 미리 설정된 경로에 설치할 경우, 둘 중 하나만 설치하는 것을 개인적으로 권장합니다.

리눅스나 유닉스의 경우 웹사이트로부터 소스 파일을 받아서 라이브러리를 빌드할 수 있습니다.

Open MPI

MPICH

macOS에서는 Homebrew를 통해서도 설치할 수 있습니다. Open MPI와 MPICH의 Homebrew 패키지 이름은 각각 open-mpi 및 mpich 이므로, 다음과 같이 brew install 명령어를 통해서 설치가 가능합니다.

Open MPI 설치

brew install open-mpi

MPICH 설치

brew install mpich

이렇게 Homebrew를 통해서 설치하는 경우, Open MPI와 MPICH 둘 다 설치해 버리면 충돌이 일어날 수 있습니다. 이는 brew info 명령어로 패키지 정보를 확인할 때도 언급되는 사항이죠. 설치가 완료되면 brew list를 이용해서 목록을 확인했을때, MPI 라이브러리가 있는 것을 볼 수 있습니다.

윈도우 사용자의 경우 vcpkg를 통해 라이브러리를 설치하면 비주얼 스튜디오에서 사용이 가능한데요. vcpkg를 사용해서 C언어 및 C++ 라이브러리들을 설치하고 관리하는 방법에 대해서는 다음 포스팅을 참고하면 좋습니다.

MPI를 이용해서 병렬 프로그램을 작성하기 위해서는, 다음과 같이 MPI 헤더 파일을 C언어 또는 C++ 소스 코드에 포함시켜야 합니다.

#include

그리고 MPI 프로그램을 컴파일 및 링크할 때는 다음과 같은 별도의 컴파일러를 사용해야 합니다.

C언어 : mpicc

C++ : mpicxx

포트란 : mpifort

MPI 프로그램을 빌드하고 나면, mpiexec라는 별도의 프로그램을 통해서 실행을 해야 되는데요. 이 때 -n 옵션을 통해서 프로세스 갯수를 지정해 줄 필요가 있습니다. 예를 들어서 쿼드코어를 사용하는 개인용 컴퓨터에서 CPU를 풀가동하고 싶다면, 4개로 설정하면 되겠습니다.

mpiexec -n [프로세스 갯수] [실행파일 이름] [명령행 인자들]

초기화 및 프로세스 랭크

MPI 병렬 프로그램에서 가장 기본이 되는 함수들은 MPI의 초기화를 담당하는 MPI_Init 함수와 MPI를 종료시키기 위한 MPI_Finalize 함수가 될 것입니다.

간단한 예시로서 “Hello World!” C언어 프로그램을 MPI를 이용해서 만들어봅시다.

#include #include #include // MPI 헤더 파일 #include int n_size_; // 프로세스의 총 갯수 int n_rank_; // 각 프로세스에 부여된 랭크 int main(int argc, char *argv[]) { // MPI 초기화 MPI_Init(&argc, &argv); // 프로세스 총 갯수 및 각 프로세스의 랭크 MPI_Comm_size(MPI_COMM_WORLD, &n_size_); MPI_Comm_rank(MPI_COMM_WORLD, &n_rank_); if (n_rank_ == 0) { // 랭크가 0 인 프로세스 fprintf(stdout, “We have %d processess.

“, n_size_); } // 모든 프로세스가 여기에 도달할 때 까지 대기 MPI_Barrier(MPI_COMM_WORLD); // Hello World! fprintf(stdout, ” [PROCESSOR %d] : Hello World!

“, n_rank_); // MPI 종료 MPI_Finalize(); return 0; }

위에도 말했다시피 MPI 프로그램의 시작은 초기화를 위한 MPI_Init 함수이고, 명령행 인자들의 포인터를 인자로 넘겨주게 됩니다. 그 다음으로는 프로세스의 총 갯수와 각 프로세스의 랭크를 알 필요가 있는데요. 프로세스의 랭크는 간단히 말하자면 각 프로세스의 아이디 역할을 하는 정수형 변수로서, 0 에서 [프로세스 총 갯수]-1 사이의 값을 가집니다.

예를 들어서 프로세스의 총 갯수와 각 프로세스의 랭크를 저장하기 위한 변수인 n_size_ 와 n_rank_ 를 각각 선언했다면, 이들의 포인터를 다음과 같이 MPI 함수에 전달할 수 있습니다.

MPI_Comm_size(MPI_COMM_WORLD, &n_size_); MPI_Comm_rank(MPI_COMM_WORLD, &n_rank_);

여기서 n_size_ 는 모든 프로세스가 당연히 동일한 값을 가지지만, n_rank_ 의 경우 프로세스마다 다른 값을 가지게 됩니다. 이 변수들을 적절히 활용해서 프로세스 간의 데이터 전달을 제어하는 거죠.

추가로 MPI_COMM_WORLD 라는 것이 등장하는데요. MPI에서는 서로 데이터를 주고받는 프로세스들의 집합체로서 커뮤니케이터 (communicator)라는 개념을 도입하고 있습니다. MPI_COMM_WORLD는 이 커뮤니케이터 중 하나로서, 프로그램의 구동에 사용되는 모든 프로세스의 집합입니다. 다시 말해서 모든 프로세스는 MPI_COMM_WORLD에 소속되어 있으므로, MPI_COMM_WORLD 커뮤니케이터를 인자로 MPI 함수들을 호출하면 모든 프로세스가 상호간에 데이터를 주고받을 수 있게 되죠.

맨 먼저 프로세스가 모두 몇 개 있는지를 출력하고 싶은데, 출력하는 구문만 넣게 되면 모든 프로세스가 그걸 실행하게 됩니다. 그래서 랭크의 값이 0인 프로세스에서만 출력할 수 있도록 n_rank_ 를 이용한 조건문을 추가했습니다. 그래서 프로세스의 총 갯수가 몇개인지에 대한 메시지는 한 번만 보면 되는거죠.

이제 “Hello World!”를 출력할 차례인데요. 소스코드 상에서는 프로세스의 총 갯수가 출력된 이후에 등장합니다만, 랭크가 0이 아닌 프로세스가 “Hello World!” 메시지를 먼저 출력해버릴 가능성이 있습니다. 이 때 서로 다른 프로세스 간의 페이스를 조절하는 한 가지 방법으로는 MPI_Barrier라는 함수를 호출하는 것입니다.

MPI_Barrier(MPI_COMM_WORLD);

인자로 들어가는 커뮤니케이터에 소속된 모든 프로세스들이 MPI_Barrier가 호출된 구문에 도달할 때 까지 대기하게 됩니다. 여기에 MPI_COMM_WORLD를 인자로 넣게 되면, 모든 프로세스들이 동기화 되겠죠.

프로그램 main 함수의 끝에는 MPI_Finalize 함수를 호출하여 MPI를 종료하도록 합시다.

위의 “Hello World!” 코드를 컴파일하고 실행해 보면, 다음과 같은 결과를 얻을 수 있습니다.

소스 코드에는 “Hello World!”를 출력하는 구문이 하나밖에 없지만, 모든 프로세스가 이를 한 번씩 실행하므로 프로세스의 갯수만큼 출력되는 것을 볼 수 있습니다.

프로세스 간의 데이터 통신

서로 다른 랭크 값을 가진 프로세스들 사이에서 변수의 값들을 전달하는게 가능하고, 이를 위해서 MPI_Send 및 MPI_Recv 함수들을 사용할 수 있습니다. MPI_Send는 다른 프로세스에 데이터를 보내는 역할을 하는 반면에, MPI_Recv는 다른 프로세스로부터 데이터를 받아오는 데 사용됩니다. 이들은 다음과 같은 프로토타입과 매개변수들을 가지고 있습니다.

/* ptr_buf : 보내고자 하는 데이터들이 * 저장된 변수나 배열의 주소 (포인터) * count : 데이터의 갯수 * 혹은 배열의 크기 * datatype : MPI 자료형 * target : 수신자 프로세스의 랭크 값 * tag : 태그 * comm : 커뮤니케이터 */ MPI_Send(void *ptr_buf, int count, MPI_Datatype datatype, int target, int tag, MPI_Comm comm); /* ptr_buf : 받고자 하는 데이터들이 * 저장된 변수나 배열의 주소 (포인터) * count : 데이터의 갯수 * 혹은 배열의 크기 * datatype : MPI 자료형 * source : 발신자 프로세스의 랭크 값 * tag : 태그 * comm : 커뮤니케이터 * ptr_status : 수신 상태가 저장되는 * 구조체의 주소 (포인터) */ MPI_Recv(void *ptr_buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *ptr_status);

송수신 함수에서 MPI 자료형을 나타내는 MPI_Datatype이 등장하는데요. C언어 자료형과 MPI 자료형들은 다음과 같이 대응됩니다.

int 정수형

MPI_INT

정수형 short int 정수형

MPI_SHORT

정수형 long int 정수형

MPI_LONG

정수형 long long int 정수형

MPI_LONG_LONG_INT

정수형 unsigned int 정수형

MPI_UNSIGNED

정수형 unsigned long int 정수형

MPI_UNSIGNED_LONG

정수형 unsigned short int 정수형

MPI_UNSIGNED_SHORT

정수형 float 실수형

MPI_FLOAT

실수형 double 실수형

MPI_DOUBLE

실수형 long double 실수형

MPI_LONG_DOUBLE

실수형 char 문자형

MPI_CHAR

문자형 unsigned char 문자형

MPI_UNSIGNED_CHAR

송수신 함수에 공통으로 들어가는 또다른 인자로는 정수형 변수인 tag가 있습니다. 이 태그는 두 프로세스가 주고받는 많은 데이터들을 구분할 수 있게 하는 역할을 하기에, 서로 대응이 되는 MPI_Send와 MPI_Recv 함수에 들어가는 태그 값을 서로 일치시켜줄 필요가 있겠습니다.

데이터를 수신하는 MPI_Recv 함수에 맨 마지막으로 들어가는 인자는 MPI_Status라는 구조체의 포인터입니다. 이 구조체는 수신 상태에 대한 정보를 저장하기 위한 것으로서, 제대로 수신된 데이터의 갯수나 함수의 호출이 (모종의 이유로) 취소되었는지 등에 대한 정보를 담고 있죠.

MPI를 이용한 데이터 송수신에 있어서 가장 주의할 점 중의 하나는 MPI_Send와 MPI_Recv 함수 간의 대응이 잘 이루어져야 한다는 것입니다. 만약 MPI_Recv 함수를 통해 데이터를 수신하고자 하는데, 발신지가 되는 프로세스에서 MPI_Send함수를 통해 데이터를 보내지 않는다면, 프로그램은 멍때린 상태로 정지하게 됩니다.

이제 원주율을 계산하는 예제 프로그램을 소개해 볼까 합니다. 원주율의 값은 표준 수학 함수 라이브러리 내에서도 정의되어 있지만, 정적분을 통해서도 구할 수 있는데요.

이는 역삼각함수인 아크탄젠트 함수의 도함수를 적분해서 원주율을 구하는 방법입니다. 자세한 사항이 궁금하시다면 다음 포스팅을 참고해 주세요.

여기서는 적분 구간을 여러개로 나눈 다음, 프로세스들에게 할당하는 방식의 병렬 프로그램을 만들어 봅시다.

test1_pi_mpi.c [다운로드]

더보기 #include #include #include #include // MPI 헤더 파일 #include int n_size_; // 프로세스의 총 갯수 int n_rank_; // 각 프로세스에 부여된 랭크 // 정밀도 double eps_precision = 1e-12; // 적분 대상이 되는 함수 double func_integrand(double u); int main(int argc, char *argv[]) { // MPI 초기화 MPI_Init(&argc, &argv); // 프로세스 총 갯수 및 각 프로세스의 랭크 MPI_Comm_size(MPI_COMM_WORLD, &n_size_); MPI_Comm_rank(MPI_COMM_WORLD, &n_rank_); if (n_rank_ == 0) { // 랭크가 0 인 프로세스 fprintf(stdout, “We have %d processes.

“, n_size_); fprintf(stdout, ”

“); } // 모든 프로세스가 여기에 도달할 때 까지 대기 MPI_Barrier(MPI_COMM_WORLD); // MPI 통신을 위한 변수들 int tag; MPI_Status status; // 현재 단계의 원주율 값 double pi_now = 0.; // 이전 단계의 원주율 값 double pi_prev; // 현재 단계의 각 프로세스의 기여분 double pi_rank = 0.; // 이전 단계의 각 프로세스의 기여분 double pi_rank_prev; // 수렴 여부를 체크하기 위한 제어 변수 int converging = 0; /* 각 프로세스에서 수치적분을 위한 구간 및 * 격자 간격 */ unsigned long int nbin_u = 1; double u_min = (double)n_rank_ / (double)n_size_; double u_max = u_min + 1. / (double)n_size_; double delta_u = fabs(u_max – u_min); int istep = 1; /* 지정한 정밀도 이내에서 수렴할 때 까지 * 반복문 실행 */ while (converging == 0) { pi_prev = pi_now; pi_rank_prev = pi_rank; pi_rank = 0.; unsigned int iu; // 수치적분 계산 if (istep == 1) { for (iu = 0; iu < nbin_u; iu++) { double u0 = u_min + delta_u * (double)iu; double u1 = u0 + delta_u; pi_rank += 0.5 * delta_u * (func_integrand(u0) + func_integrand(u1)); } } else { pi_rank = 0.5 * pi_rank_prev; for (iu = 0; iu <= nbin_u; iu++) { if (iu % 2 == 0) { continue; } double u_now = u_min + delta_u * (double)iu; pi_rank += delta_u * func_integrand(u_now); } } pi_now = 0.; if (n_rank_ == 0) { // 랭크가 0 인 프로세스 /* 모든 프로세스의 기여분들을 취합하여 * 원주율의 값 계산 */ pi_now = pi_rank; for (int irank = 1; irank < n_size_; irank++) { tag = 1000 + irank; double pi_add; MPI_Recv(&pi_add, 1, MPI_DOUBLE, irank, tag, MPI_COMM_WORLD, &status); pi_now += pi_add; } fprintf(stdout, " step %d : pi = %.12f ", istep, pi_now); } else { // 랭크가 0 이 아닌 프로세스 tag = 1000 + n_rank_; MPI_Send(&pi_rank, 1, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD); } if (n_rank_ == 0) { // 랭크가 0 인 프로세스 // 수렴 체크 if (fabs(pi_now - pi_prev) < 0.5 * eps_precision * fabs(pi_now + pi_prev)) { converging = 1; } for (int irank = 1; irank < n_size_; irank++) { tag = 2000 + irank; MPI_Send(&converging, 1, MPI_INT, irank, tag, MPI_COMM_WORLD); } } else { // 랭크가 0 이 아닌 프로세스 tag = 2000 + n_rank_; MPI_Recv(&converging, 1, MPI_INT, 0, tag, MPI_COMM_WORLD, &status); } istep += 1; // 적분 구간의 격자 갯수를 2배로 증가 nbin_u = 2 * nbin_u; delta_u = 0.5 * delta_u; } // 모든 프로세스가 여기에 도달할 때 까지 대기 MPI_Barrier(MPI_COMM_WORLD); if (n_rank_ == 0) { // 랭크가 0 인 프로세스 fprintf(stdout, " "); fprintf(stdout, "pi from numerical integration "); fprintf(stdout, " > pi = %.12f

“, pi_now); fprintf(stdout, “pi from C math library

“); fprintf(stdout, ” > pi = %.12f

“, M_PI); } // MPI 종료 MPI_Finalize(); return 0; } double func_integrand(double u) { return 2. / (fabs(u * u) + fabs((1. – u) * (1. – u))); }

프로그램을 컴파일하고 실행하면, 원주율의 값이 출력됩니다. 또한 여러 단계를 거치면서, 그 값이 더 정밀해지는 것도 확인이 가능하죠.

결과적으로 표준 수학 함수 라이브러리에 정의된 것과 상당히 근접한 값을 얻었습니다.

이상으로 간단한 예제 프로그램들을 통해서 MPI 병렬 프로그램의 뼈대를 이루는 요소들을 짚어보았습니다. 이번 포스팅에서는 C언어를 기준으로 이야기했습니다만, 앞서 언급한대로 C++ 및 포트란에서도 사용이 가능합니다. 뿐만 아니라 다양한 기능을 가진 함수들이 많이 있는데요. 이들은 다음 웹사이트에 PDF 문서로 잘 요약되어 있습니다.

people.cs.vt.edu/npolys/IT/FDI/bootcamp_2008/uva_mats

병렬 프로그램을 작성하기 위한 또 다른 방법으로서 OpenMP에 대해 서론에서 언급했었는데요. OpenMP를 이용해 병렬 프로그램을 만드는 방법에 대해서는 다음 포스팅을 참고하면 좋습니다.

본문에서 명령행 인자가 몇 번 등장한 바 있습니다. 이는 프로그램을 실행할 때 실행파일의 이름과 함께 커맨드 라인에 입력하는 인자들이죠. 자세한 사항은 다음 포스팅에 소개되어 있습니다.

MPI 병렬 프로그래밍

출판사 리뷰

이제는 멀티코어 병렬컴퓨팅 시대이다!

흔히 ‘슈퍼컴퓨터’하면 기상청의 날씨관측에 쓰이는 등 과학기술 분야의 전유물로만 인식하고 있지만 최근의 슈퍼컴퓨터는 국가안보, 금융, 게임, 영화, 문화 콘텐츠 제작 등 다양한 분야에 쓰이고 있다. 그러나 아직까지도 일반인들에게는 그다지 친숙하지 않은 것이 현실이다. 그러나 이제는 여러 개의 CPU가 협력하여 큰 계산을 수행하는 병렬형 슈퍼컴퓨터로 대체되면서 개인용 PC도 머잖아 병렬처리로 구성될 수밖에 없는 시대가 왔다.

이 책은 컴퓨터 프로그래머, 소프트웨어 개발자, 설계자, 연구자는 물론 전산학 학생들에게도 많은 도움을 제시할 것이다. 또한 컴퓨터 관련 전공자나 종사자 뿐 아니라 일반인들에게도 슈퍼컴퓨터 및 병렬프로그래밍이라는 개념을 이해할 수 있도록 도와줄 것이다.

이 책은 슈퍼 컴퓨터 병렬 프로그래밍 매뉴얼이다. 병렬 처리 관련 기능에 어떤 것이 있고, 어떻게 사용하는지에 대한 방법뿐 아니라, 병렬 프로그램 설계와 구현 노하우를 전수한다.

본문은 MPI의 소개와 개요, MPI 프로그램의 기본 구조, 점대점 통신, 집합 통신, 유도 데이터 타입(Derived Data Type), 가상 토폴로지(Virtual Topology) 등 8개의 장과 본문에서 다룬 예제들을 총정리하는 부록으로 구성되어 있다. 도입부와 중간까지는 메시지 패싱(message passing) 프로그래밍에 대한 설명과 점대점 통신에 대한 개념, 본격적으로 MPI를 이용한 병렬프로그래밍에 대해 설명한다.

MPI는 “Message Passing Interface”의 약어로서 프로세스들 사이의 통신을 위해 코드에서 호출해 사용하는 서브루틴(Fortran) 또는 함수(C)들의 라이브러리이다. MPI는 Fortran 또는 C로 작성된 메시지 패싱 프로그램들에게 순차 프로그램들처럼 다양한 아키텍처들에 대한 풍부한 소스코드 이식성(source code portability)을 제공하고자 하는 표준화 작업의 결과이다.

MPI 프로그램은 MPI 환경 초기화, MPI 환경종료로 구성되는 기본적인 골격을 가진다. 사용자는 이러한 기본골격에 자신의 코드를 추가하여 전체적인 병렬코드를 작성해 나가게 된다.

점대점(point to point) 통신은 두 프로세스 사이의 통신이며 이때 두 프로세스는 메시지를 보내는 송신 프로세스와 메시지를 받는 수신 프로세스가 된다. 송신 프로세스와 수신 프로세스 간의 메시지 전송에 이용된 메모리 위치에 안전하게 접근할 수 있게 되었을 때 통신이 완료되었다고 말한다.

실제 MPI를 이용한 병렬 프로그램 작성 시, 모든 프로세스들이 공유 파일 시스템으로부터 입력파일을 읽어오는 경우에는 모두 동일한 파일로부터 데이터를 읽어들인다. 또한 프로세스가 입력파일의 복사본을 각각 따로 가지는 경우에는 프로그램을 실행하기 전 각 프로세스들의 로컬 파일 시스템에 입력 파일을 복사해 두는 방법으로 진행하면 된다.

병렬 프로그래밍에 대한 하나의 아키텍처적 접근방식을 제시하는 《멀티코어 시대에 꼭 알아야 할 MPI 병렬 프로그래밍》은 컴퓨터 프로그래머, 소프트웨어 개발자, 설계자, 연구자, 소프트웨어 아키텍트는 물론 전산학 학생들에게도 많은 도움을 제시할 것이다. 또한 일반인들에게도 슈퍼컴퓨터 및 병렬프로그래밍이라는 개념을 이해할 수 있도록 도와줄 것이다.

MPI Program

1. 병렬 프로그램

병렬프로그램이 어떤 것인지를 알기위해서 먼저 가장 간단한 병렬 프로그램을 살펴보자. 2개의 프로세서가 사용자로부터 정수값 n1, n2를 입력받아 n1~n2를 더하는 병렬프로그램을 고려해보자. 각 프로세스는 아래와 같은 작업을 수행하게 된다.

시간 프로세스-1 프로세스-2 1

2

3

4

5

6

사용자로부터 n1,n2를 입력받는다.

n1,n2를 두 개의 작업( n1~m , m+1~n2)로 나눈다.

프로세스-2에게 메시지(m+1~n2)를 보낸다.

n1~m을 더한 결과 result-1을 구한다.

프로세스-2로부터 메시지(result-2)를 받는다.

result-1 과 result-2를 더한후 출력하고 종료한다. 프로세스-1으로부터의 메시지를 기다린다.

프로세스-1으로부터의 메시지를 기다린다.

프로세스-1으로부터의 메시지(m+1~n2)를 받는다.

m+1~n2을 더한결과 result-2을 구한다.

프로세스-1에게 메시지(result-2)를 보낸다.

프로그램을 종료한다.

매우 간단한 알고리즘을 갖고 있지만, 실제 프로그램에 있어서는 네트워크를 통해 연결을 맺고 데이터를 전달해주는 일련의 절차를 거쳐야 한다. 즉 네트워크 프로그램이 된다. 일반적으로 메시지 패싱은 많은 다양한 형태로 자주 일어나므로 이러한 것은 매우 비효율적이다. 그래서 등장한 것이 병렬 라이브러리다.

병렬 라이브러는 사용자에게 메시지 패싱에 필요한 다양한 함수를 제공해줌으로써 프로그램 개발에 필요한 노력을 줄여주고 좀더 신뢰성있는 프로그램을 가능하게 하였다. 이중 국제표준으로 채택된 MPI는 1992년 처음으로 MPI-1 이 정의되었으며 현재 최신버전은 MPI-2 이다. 이후 설명할 병렬 프로그램은 이 MPI를 이용할 것이다. 정확하게 말하면 MPI자체는 병렬라이브러리를 위한 규약이다. 그러나 이 규약을 따르는 많은 라이브러리들을 통칭하여 MPI라고 부르기도 한다.

MPI규약을 따르는 많은 라이브러리들이 있다. 그중 가장 널리 사용되고 있는 것은 Ohio Supercomputer Center 에서 개발한 LAM MPI , Argonne National Laboratory에서 개발한 MPICH 두 개를 들 수 있다. 그러나 어떠한 병렬라이브러리를 사용하여 작성하든지 이들 모두 MPI규약을 따르므로 소스코드가 100% 호환된다는 장점이 있다. 이외에도 PVM 이라는 라이브러리도 있다.

. 영역분할과 함수분할

문제를 병렬로 풀기위해서는 크게 2가지 방법 즉 함수적 분할 (functional decomposition) 과 영역 분할 (domain decomposition)이 있다. 이중 함수적 분할법은 널리 사용되지 않고 있다. 그럼 간단한 예제를 통하여 함수적 분할과 영역분할에 대해 알아보자. 아래는 예제로 사용할 시리얼 코드이다.

do i=1, 100

var1(i) = var2(i)+var3(i)

var4(i) = var5(i)+var6(i)

end do

위와 같은 문제를 2개의 프로세스를 사용하여 함수분할을 사용하여 푼다면 아래와 같이 쓸수있다.

if ( process1 )

{ do i=1, 100

var1(i) = var2(i)+var3(i)

end do

}

if ( process2 )

{ do i=1, 100

var4(i) = var5(i)+var6(i)

end do

}

위와같이 함수 분할에서는 각 프로세스는 하는 일이 서로 다르다. 어떤 프로세스는 var1을 갱신하고 어떤 프로세스는 var4를 갱신한다. 그러나 이러한 방식은 프로그램의 확장성(scalibility)를 제한하고 로드 밸런싱이 어려운 단점이 있다.

그렇다면 동일한 시리얼 프로그램을 영역 분할을 사용하여 풀어보자. 그러면 아래와 같이 쓸수 있다. 각 프로세스는 동일하게 var1, var4를 갱신하지만 다루는 data가 다르다.

if ( process1 )

{ do i=1, 50

var1(i) = var2(i)+var3(i)

var4(i) = var5(i)+var6(i)

end do

}

if ( process2 )

{ do i=51, 100

var1(i) = var2(i)+var3(i)

var4(i) = var5(i)+var6(i)

end do

}

위의 영역분할법은 확장성이 좋으며 로드밸런싱에서도 유리하다. 따라서 대부분의 병렬화가 영역분할법을 사용한다. 그러나 모든 경우 영역분할이 유리한 것은 아니다. 데이터 의존성이 없다면 함수분할법은 더 좋은 성능을 제공할 수도 있다

. MPI에서 제공하는 함수들

3-1. 가장 기본적인 6개의 함수

MPI에서는 120개가 훨씬 넘는 무수히 많은 함수들을 정의해 놓고 있다. 이들 대부분은 6개의 기본적인 함수들의 조합으로 구현될 수 있으며 이들 함수는 아래와 같다.

MPI_Init(&argc, &argv)

프로그램 실행 인수들과 함께 mpi함수들을 초기화 해준다.

MPI_Finalize()

mpi함수들을 종료한다. 모든 mpi함수들은 MPI_Inti() 과 MPI_Finalize() 사이에서 호출되어야 한다.

int MPI_Comm_rank(MPI_Comm comm, int *rank)

comm 커뮤니케이터에서 자신의 프로세스 id를 얻는다.

int MPI_Comm_size(MPI_Comm comm, int *size)

comm 커뮤니케이터에서 실행되는 프로세스의 개수를 얻는다.

int MPI_Send(void *message, int count, MPI_Datatupe datatype, int dest, int tag, MPI_Comm comm)

dest로 메시지를 보낸다.

message는 보내고자 하는 메시지를 저장하고 있는 버퍼

count 는 보낼 메시지 개수

datatype는 보낼 메시지 타입

dest는 보내고자 하는 프로세스 id

tag는 보내는 메시지에 대한 꼬리표

comm은 dest와 자신의 프로세스가 속해있는 커뮤니케이터

int MPI_Recv(void *message, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

source로부터 메시지를 받는다.

message는 받은 메시지를 저장할 버퍼

count는 받을 메시지 개수(받는 메시지갯수보다 작으면 에러발생)

datatype은 받을 메시지 타입

source는 메시지를 보내주는 프로세스 id

tag는 받은 메시지를 확인하기 위한 꼬리표(MPI_Recv에서의 tag와 MPI_Send에서의 tag가 같아야한다)

comm은 source와 자신의 프로세스가 속해있는 커뮤니케이터

status는 실제받은 데이터에 대한 정보(source와 tag)

예제 프로그램

#include

#include “mpi.h”

int main(int argc, char **argv)

{ int rank, size;

char data[10];

MPI_Status status;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

if(rank == 0)

{ strcpy(data, “process 0”);

// MPI_CHAR 는 전송하는 데이터가 char 타입이라는 데이터 타입 선언이다.

MPI_Send(data, 10, MPI_CHAR, 1, 123, MPI_COMM_WORLD);

}

else if(rank == 1)

{ MPI_Recv(data, 10, MPI_CHAR, 0, 123, MPI_COMM_WORLD, &status);

printf(“message=%s, source=%d, tag=%d

“, data, status.MPI_SOURCE, status.MPI_TAG);

}

MPI_Finalize();

return 0;

} 예제 실행과 결과 위의 소스를 mpitest.c 로 저장한후 아래와 같은 일련의 과정을 거쳐서 수행해보자. [scshin@atom scshin]$ cat lamhosts

node1

node2

[scshin@atom scshin]$ lamboot -v lamhosts

LAM 6.3.2/MPI 2 C++ – University of Notre Dame

Executing hboot on n0 (node1)…

Executing hboot on n1 (node2)…

topology done

[scshin@atom scshin]$ hcc -o mpitest mpitest.c -lmpi

[scshin@atom scshin]$ mpirun -np 2 ./mpitest

message=process 0, source=0, tag=123

[scshin@atom scshin]$

3-2. Collective Communication 커뮤니케이터에 있는 프로세스들이 모두 호출되어야 하는 함수이다. 커뮤니케이터란 프로세스 그룹을 말한다. 기본적으로 MPI프로그램에서는 MPI_COMM_WORLD라는 기본 커뮤니케이터가 생성된다. 이는 동시에 수행되는 모든 프로세스를 포함한다. 그러나 사용자는 임의의 프로세스로 구성된 새로운 커뮤니케이터를 생성할 수가 있다. Collective Communication 함수들은 어떤 커뮤니케이터안의 모든 프로세스가 같이 모두 호출하여야 하는 함수들이다. int MPI_Bcast(void *message, int count, MPI_Datatype datatype, int root, MPI_Comm comm) comm 커뮤티케이터에 속한 모든 프로세스들에게 동일한 message를 전송한다.

root는 메시지를 뿌려주는 프로세스 id.

root의 message에만 보내고자 하는 데이터가 들어있고, 다른 프로세스의 message는 받은 메시지를 저장할 공간이다. int MPI_Reduce(void *operand, void *result, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) 모든 프로세스들이 MPI_Reduce를 수행하면 모든 operand가 op에 따라 연산을 수행하고 그 결과가 root 프로세스의 result에 저장된다.

operand는 연산이 적용될 피연산자

result는 연산결과가 저장될 버퍼

op는 어떤 종료의 연산이 수행될것인지를 알려주는 OP-CODE

root는 연산결과가 저장될 프로세스 id int MPI_Barrier(MPI_Comm comm) comm 커뮤니케이터에 속한 모든 프로세스들이 MPI_Barrier를 호출할때까지 block시킴으로서 동기화를 시킨다. int MPI_Gather(void *send_buf, int send_count, MPI_Datatype send_type, void *recv_buf, int recv_count, MPI_Datatype recv_type, int root, MPI_comm comm) root프로세스는 각 프로세스들이 보내준 자료(send_buf)를 프로세스 id 순으로 root의 recv_buf에 차곡차곡 쌓는다. int MPI_Scatter(void *send_buf, int send_count, MPI_Datatype send _type, void *recv_buf, int recv_count, MPI_Datatyp recv_type, int root,MPI_Comm comm) send_buf의 내용을 send_count의 크기로 잘라서 모든 프로세스들의 recv_buf로 순서대로 전송한다. MPI_Gather와는 반대의 역할 int MPI_Allgather(void *send_buf, int send_count, MPI_Dataltype send_type, void *recv_buf, int recv_count, MPI_Datatype recv_type, MPI_comm comm) MPI_gather와 마찬가지로 모든 프로세스의 send_buf의 내용을 모으나, 모든 프로세스의 recv_buf에 저장하는 것이 다르다. int MPI_Allreduce(void *operand, void *result, int count, MPI_Datatype datatype, MPI_Op, MPI_Comm comm) MPI_Reduce와 마찬가지로 모든 프로세스의 operand에 op연산을 적용하지만 그 결과를 모든 프로세스의 result가 가지게 된다. 예제 프로그램

#include

#include “mpi.h”

int main(int argc, char **argv)

{ int rank, size;

int data=10;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

// 아래의 코드중 MPI_SUM 은 덧셈을 수행하라는 연산타입 선언이다.

MPI_Reduce(&data, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);

if(rank = 0) printf(“result = %d

“,result);

MPI_Finalize();

return 0;

} 3-3. Crouping Data for Communication 주로 여러개의 데이터들을 모아서 한번에 전송하도록 해주는 함수들로 구성되어 있다. 이러한 함수들이 필요한 이유는 일반적으로 잦은 메시지패싱보다는 이들을 묶어서 한번에 보내주는 것이 효율면에서 좋기 때문이다. int MPI_Type_Struct(int count, int *array_of_block_lengths, MPI_Aint, array_of_displacements, MPI_Datatype *array_of_types, MPI_Datatype *newtype) C언어에서 새 데이터형을 선언했을때, 그형에 대응하는 MPI형을 선언한다.

만약 struct test {int a[100]; float[50]; double c;} *N; 라는 새로운 형을 선언한후, 그에 대응하는 MPI형을 만든다면

count는 새 데이터형에 포함될 변수형의 개수인 3,

array_of _block_lengths는 포함될 array의 길이인 {100, 50, 1},

array_of_displacements는 새로운 데이터형에서의 각 필드의 offset인 { &(N->a) – N, &(N->b) – N, &(N->c) -N }

array_of_types은 MPI형 변수타입인 {MPI_Int, MPI_Float, MPI_Double}

newtype은 사용자가 원하는 테이타형 이름 MPI_Test를 사용하면 된다. MPI_Type_commit(MPI_Datatype *newtype) MPI_Type_Struct에서 선언해준 새데이타형을 MPI에서 사용할수 있게 한다. int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) 불연속적인 메모리에 위치한 데이터를 연속적인 메모리처럼 사용할수 있다. int MPI_Type_vector(int count, int block_length, int stride, MPI_Datatype element_type, MPI_Datatype *newtype) 규칙적인 길이, 규칙적인 간격을 갖는 아래 형태의 구조를 선언시 MPI_Type_vector(3, 2, 2, MPI_Int, MPI_Newtype) 1 2 3 4 5 6 int MPI_Type_indexed(int count, int *array_of_block_lengths, int *array_of_displacements, MPI_Datatype element_type, MPI_Datatype *newtype) 불규칙적인 길이, 불규칙적인 간격을 갖는 배열을 새로운 타입으로 선언할시

array_of_block_lengths는 각 블록의 길이인 {2, 1, 3}

array_of_displacements는 각 불록의 offset 1 2 3 4 5 6

int MPI_Pack(void *pack_data, int in_count, MPI_Datatype datatype, void *buffer, int size, int *position_ptr, MPI_Comm comm)

pack_data에 있는 count개의 데이터를 buffer에 추가해준다.

position_ptr은 데이터가 저장될 buffer 위치의 index이며, 압축후에는 자동 증가, size는 buffer의 byte 크기

int MPI_Unpack(void *buffer, int size, int *position_ptr, void *unpack_data, int count, MPI_Datatype datatype, MPI_comm comm)

MPI_Pack으로 압축된 데이터를 풀어준다.

buffer는 압축된 데이터가 저장된 메모리

position_ptr은 압축된 데이터 buffer의 첫 번째 index로 unpack후에 자동증가

size는 버퍼의 byte 크기

count개의 데이터를 풀어서 datatype형으로 unpack_data에 복사해준다.

3-4. Communicators and Topologies

다양한 커뮤니케이터를 만들고 프로세서들의 위상을 선언할 수 있는 함수들로 구성된다.

int MPI_Comm_group(MPI_Comm comm, MPI_Group *group)

comm에 포함된 프로세스 그룹을 얻어온다.

int MPI_Group_incl(MPI_Group old_group, int new_group_size, int *ranks_in_old_group, MPI_Group *new_group)

old_group에서 rank_in_old_group의 id를 가지고 있는 new_group_size개수의 프로세스들로 새로운 그룹 new_group을 만든다.

int MPI_Comm_creat(MPI_Comm old_comm, MPI_Group new_group, MPI_Comm *new_comm)

그룹을 커뮤니케이터로 만들어준다. (이로써 서로간의 통신이 가능해진다.)

MPI_Comm_group, MPI_Group_incl와는 달리 Collective operation -단독으로 실행되서는 안되고, 반드시 모든 프로세스가 동시에 수행되야 하는 명령이다.

int MPI_Comm_split(MPI_Comm old_comm, int split_key, int rank_key, MPI_Comm *new_comm)

동일한 split_key로 호출된 프로세스들을 묶어서 동일한 커뮤니케이터로 만든다.

rank_key는 프로세스 rank를 결정할 때 작은순서대로 작은 id를 부여받는다.

프로세스 0, 1, 2번은 split_key 1로 호출하고, 프로세스 3, 4, 5번은 split_key 2로 호출했을 때, 동일한 이름(new_comm)의 두 개의 커뮤니케이터가 생성된다. 만약 0번 프로세스에서 new_comm으로 MPI_Bcast를 호출하면 0, 1, 2번으로 전송되고, 3번 프로세스에서 new_comm으로 MPI_Bcast를 호출하면 3, 4, 5번으로 전송된다.

int MPI_Cart_create(MPI_Comm old_comm, int number_of_dims, int *dim_sizes, int *periods, int reorder, MPI_Comm *cart_comm)

새로운 커뮤니케이터 cart_comm을 생성해준다.

old_comm과 cart_comm에 속해있는 프로세스들은 같지만 그들의 id는 같지 않다.

cart_comm의 프로세스들은 number_of_dims차원의 매트릭스(dim_size *dim_size …)로 재구성되며, 그에 맞게 새로운 id를 갖게 된다.

periods는 각 dimention이 circular인지 linear인지의 flag.

reorder는 재구성을 하면서 프로세스 id변환을 허용하는 flag.

int MPI_Cart_rank(MPI_Comm comm, int *coordinates, int *rank)

coordinates[]의 정보를 가지고 그에 해당하는 프로세스의 rank를 구한다.

coordinates[]={2,4} 이면 프로세스의 매트릭스에서 2행4열의 프로세스 id를 리턴한다.

coordinates[]는 몇열 몇행의 정보를 가지고 있다.

int MPI_Cart_coords(MPI_Comm comm, int rank, int number_of_dims, int *coordinates)

rank를 가지고 그에 해당하는 coordinates[]를 구한다.

2행4열에 위치한 프로세스 id가 6일때, rank=6로 함수를 호출하면 coordinates[]={2,4}리턴 한다.

int MPI_Cart_sub(MPI_Comm grid_comm, int varying_coords, MPI_Comm *comm)

2 by 2 매트릭스인경우 2개의 커뮤니케이터를 만든다.

MPI_Cart_sub(grid_comm, {0,1}, comm) 을 사용하여 각 열을 동일한 커뮤니케이터로 묶어준다.

varying_coords[]는 각dimention이 comm에 속하는지를 알려주는 boolean

MPI 병렬 프로그래밍 – 교보문고

흔히 ‘슈퍼컴퓨터’하면 기상청의 날씨관측에 쓰이는 등 과학기술 분야의 전유물로만 인식하고 있지만 최근의 슈퍼컴퓨터는 국가안보, 금융, 게임, 영화, 문화 콘텐츠 제작 등 다양한 분야에 쓰이고 있다. 그러나 아직까지도 일반인들에게는 그다지 친숙하지 않은 것이 현실이다. 그러나 이제는 여러 개의 CPU가 협력하여 큰 계산을 수행하는 병렬형 슈퍼컴퓨터로 대체되면서 개인용 PC도 머잖아 병렬처리로 구성될 수밖에 없는 시대가 왔다.이 책은 컴퓨터 프로그래머, 소프트웨어 개발자, 설계자, 연구자는 물론 전산학 학생들에게도 많은 도움을 제시할 것이다. 또한 컴퓨터 관련 전공자나 종사자 뿐 아니라 일반인들에게도 슈퍼컴퓨터 및 병렬프로그래밍이라는 개념을 이해할 수 있도록 도와줄 것이다.이 책은 슈퍼 컴퓨터 병렬 프로그래밍 매뉴얼이다. 병렬 처리 관련 기능에 어떤 것이 있고, 어떻게 사용하는지에 대한 방법뿐 아니라, 병렬 프로그램 설계와 구현 노하우를 전수한다.본문은 MPI의 소개와 개요, MPI 프로그램의 기본 구조, 점대점 통신, 집합 통신, 유도 데이터 타입(Derived Data Type), 가상 토폴로지(Virtual Topology) 등 8개의 장과 본문에서 다룬 예제들을 총정리하는 부록으로 구성되어 있다. 도입부와 중간까지는 메시지 패싱(message passing) 프로그래밍에 대한 설명과 점대점 통신에 대한 개념, 본격적으로 MPI를 이용한 병렬프로그래밍에 대해 설명한다.MPI는 “Message Passing Interface”의 약어로서 프로세스들 사이의 통신을 위해 코드에서 호출해 사용하는 서브루틴(Fortran) 또는 함수(C)들의 라이브러리이다. MPI는 Fortran 또는 C로 작성된 메시지 패싱 프로그램들에게 순차 프로그램들처럼 다양한 아키텍처들에 대한 풍부한 소스코드 이식성(source code portability)을 제공하고자 하는 표준화 작업의 결과이다.MPI 프로그램은 MPI 환경 초기화, MPI 환경종료로 구성되는 기본적인 골격을 가진다. 사용자는 이러한 기본골격에 자신의 코드를 추가하여 전체적인 병렬코드를 작성해 나가게 된다.점대점(point to point) 통신은 두 프로세스 사이의 통신이며 이때 두 프로세스는 메시지를 보내는 송신 프로세스와 메시지를 받는 수신 프로세스가 된다. 송신 프로세스와 수신 프로세스 간의 메시지 전송에 이용된 메모리 위치에 안전하게 접근할 수 있게 되었을 때 통신이 완료되었다고 말한다.실제 MPI를 이용한 병렬 프로그램 작성 시, 모든 프로세스들이 공유 파일 시스템으로부터 입력파일을 읽어오는 경우에는 모두 동일한 파일로부터 데이터를 읽어들인다. 또한 프로세스가 입력파일의 복사본을 각각 따로 가지는 경우에는 프로그램을 실행하기 전 각 프로세스들의 로컬 파일 시스템에 입력 파일을 복사해 두는 방법으로 진행하면 된다.병렬 프로그래밍에 대한 하나의 아키텍처적 접근방식을 제시하는 《멀티코어 시대에 꼭 알아야 할 MPI 병렬 프로그래밍》은 컴퓨터 프로그래머, 소프트웨어 개발자, 설계자, 연구자, 소프트웨어 아키텍트는 물론 전산학 학생들에게도 많은 도움을 제시할 것이다. 또한 일반인들에게도 슈퍼컴퓨터 및 병렬프로그래밍이라는 개념을 이해할 수 있도록 도와줄 것이다. 닫기

MPI 병렬 프로그래밍 기초 – 0. 병렬 프로그래밍?

안녕하세요. 이번에는 “병렬 프로그래밍 이야기”라는 카테고리로 글을 쓰게 되었습니다. 말 그대로 병렬 프로그래밍에 관련된 자료를 정리할 예정입니다.

병렬 프로그래밍이라는 단어가 별로 익숙치 않으시는 분도 많으실 거 같은데요, 말 그대로 ‘한 작업을 여러 컴퓨터에게 나누어 일을 시키는 작업’입니다. 그냥 알아서 나눠서 시키면 되지 않을까? 란 생각을 하시는 분도 계실지 모르지만, 이 작업이 그렇게 간단하게 알아서 되는 작업은 아닙니다. 직접 병렬화 코드를 짜 주어야 합니다.

이 때, 병렬화를 위해서 자주 쓰이는 몇가지 언어가 있습니다. OpenMP, OpenMPI, OpenACC 등이 있지요. 저는 그 중에서도 MPI에 대해 정리를 해 볼 생각입니다.

왜 그런고 하니, 제가 병렬 프로그래밍 관련 자료를 열심히 찾아보던 중에, 한글로 된 MPI 관련 자료가 그리 많지 않다는 사실을 깨달아서 직접 정리를 해 보면서 공부도 하자! 라는 생각에 시작하였습니다.

메시지 전달 인터페이스(Message Passing Interface, MPI)는 주로 C와 Fortran에서 쓰이는 병렬화 프로그래밍입니다. 각각의 프로세스를 관리할 수 있고, 각 프로세스마다 통신을 하며 작업을 할 수 있게 되어있죠.

먼저 MPI 시스템의 기본 구조를 정리하는 것 부터 시작하여, 점 대 점 통신, 집합 통신, 토폴로지 등의 내용을 정리할 예정이구요, 예제들도 이곳저곳에서 찾아보며 작성해 볼 생각입니다.

그럼 같이 빢치는 재밌는 병렬 프로그래밍을 공부해 봅시다!

키워드에 대한 정보 mpi 병렬 프로그래밍

다음은 Bing에서 mpi 병렬 프로그래밍 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 C ++의 실용적인 병렬 처리 : MPI 기본 사항

  • Crash Course
  • programming
  • computer science
  • computer engineering
  • coding
  • teaching
  • education
  • learning
  • mpi
  • message passing
  • shared memory
  • address space
  • rank
  • communicator

C #++의 #실용적인 #병렬 #처리 #: #MPI #기본 #사항


YouTube에서 mpi 병렬 프로그래밍 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 C ++의 실용적인 병렬 처리 : MPI 기본 사항 | mpi 병렬 프로그래밍, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

Leave a Comment