Parallel Programming in MPI part 1 情報ネットワーク特論 南里 豪志 1 1 Preparation: Request for your account of the server • もし、公開鍵暗号方式の鍵を作っていなければ、作成する If you haven't created a pair of keys of public key cryptosystem, create them. • http://okaweb.ec.kyushu-u.ac.jp/lectures/in-ng/2014/pki-2014.pptx • メールに「公開鍵」を添付し、本文に学籍番号と名前を書いて以下 に送付 Send a mail to the following address with your public key attached and your student ID and name are written in the body of it. • [email protected] • Your account information will be sent later. 2 「並列プログラミング実習」の目的 Purpose of “parallel programming tutorial” • 「通信」 = 複数のプロセス間でのデータの送受信 “Communication” = Data transfer among multiple processes. • 複数のプロセスが並行してそれぞれのプログラムを実行 Each of the processes executes its own program concurrently. • これが並列処理 This is “parallel processing”. • 並列処理には「並列プログラム」が必要 “Parallel program” is required for parallel processing Learn how to write “parallel programs”. 3 どうやって、プログラムに通信を記述するか? How to Describe Communications in a Program? • TCP, UDP ? • Good: - 多くのネットワークに実装されており,可搬性が高い. Portable: Available on many networks. • Bad: - 接続やデータ転送の手続きが複雑 Protocols for connections and data-transfer are complicated. 記述可能だが,プロトコル関連の記述が必要。 Possible. But require additional descriptions for protocols. 4 MPI (Message Passing Interface) • 並列計算向けに設計された通信関数群 A set of communication functions designed for parallel processing • C, C++, Fortranのプログラムから呼び出し Can be called from C/C++/Fortran programs. • "Message Passing" = Send + Receive • 実際には,Send, Receive 以外にも多数の関数を利用可能. Actually, more functions other than Send and Receive are available. • ともかく、プログラム例を見てみましょう Let's see a sample program, first. 5 #include <stdio.h> #include "mpi.h" int main(int argc, char *argv[]) { int myid, procs, ierr, i; double myval, val; MPI_Status status; FILE *fp; char s[64]; Setup MPI environment MPI_Init(&argc, &argv); Get own ID (= rank) of the process MPI_Comm_rank(MPI_COMM_WORLD, &myid); Get total number of processes MPI_Comm_size(MPI_COMM_WORLD, &procs); If my ID is 0 if (myid == 0) { fp = fopen("test.dat", "r"); input data for this process and keep it in myval fscanf(fp, "%lf", &myval); i = 1~procs-1 for (i = 1; i < procs; i++){ input data and keep it in val fscanf(fp, "%lf", &val); MPI_Send(&val, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD); } use MPI_Send to send value in val to process i fclose(fp); } else MPI_Recv(&myval, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status); processes with ID other than 0 use MPI_Recv to receive data from process 0 and keep it in myval printf("PROCS: %d, MYID: %d, MYVAL: %e\n", procs, myid, myval); MPI_Finalize(); print-out its own myval end of parallel computing return 0; } 6 6 プログラム例の実行の流れ Flow of the sample program. • 複数の"プロセス"が,自分の番号(ランク)に応じて実行 Multiple "Processes" execute the program according to their number (= rank). rank 0 read data from a file read data from a file myval send val to rank 2 print myval rank 2 receive data from rank 0 receive data from rank 0 val wait for the arrival of the data send val to rank 1 read data from a file rank 1 myval val print myval wait for the arrival of the data myval print myval 7 実行例 Sample of the Result of Execution • 各プロセスがそれぞれ勝手に表示するので、表示の順番は毎回変 わる可能性がある。 The order of the output can be different, since each process proceeds execution independently. PROCS: PROCS: PROCS: PROCS: 4 4 4 4 MYID: MYID: MYID: MYID: 1 2 0 3 MYVAL: MYVAL: MYVAL: MYVAL: 20.0000000000000000 30.0000000000000000 10.0000000000000000 40.0000000000000000 rank rank rank rank 1 2 0 3 8 MPIインタフェースの特徴 Characteristics of MPI Interface • MPI プログラムは,普通の C言語プログラム MPI programs are ordinal programs in C-language • Not a new language • 各プロセスが同じプログラムを実行する Every process execute the same program • ランク(=プロセス番号)を使って,プロセス毎に違う仕事を実行 Each process executes its own work according to its rank(=process number) • 他のプロセスの変数を直接見ることはできない。 A process cannot read or write variables on other process directly Rank 0 Read file Read file myval Rank 2 val Receive Send Read file Rank 1 val Receive myval Print myval Send Print myval myval Print myval 9 9 TCP, UDP vs MPI • MPI:並列計算に特化したシンプルな通信インタフェースSimple interface dedicated for parallel computing • SPMD(Single Program Multiple Data-stream) model • 全プロセスが同じプログラムを実行 All processes execute the same program • TCP, UDP: 各種サーバ等,様々な用途を想定した汎用的な通信イ ンタフェース Generic interface for various communications, such as internet servers • Server/Client model • 各プロセスが自分のプログラムを実行 Each process executes its own program. 10 TCP Client sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = inet_addr(servIP); echoServAddr.sin_port = htons(echoServPort); connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)); echoStringLen = strlen(echoString); send(sock, echoString, echoStringLen, 0); initialize int main(int argc, char *argv[]) { int myid, procs, ierr, i; double myval, val; MPI_Status status; FILE *fp; char s[64]; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &procs); if (myid == 0) { fp = fopen("test.dat", "r"); fscanf(fp, "%lf", &myval); for (i = 1; i < procs; i++){ fscanf(fp, "%lf", &val); MPI_Send(&val, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD); } fclose(fp); } else MPI_Recv(&myval, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status); totalBytesRcvd = 0; printf("Received: "); while (totalBytesRcvd < echoStringLen){ bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0); totalBytesRcvd += bytesRcvd; echoBuffer[bytesRcvd] = '\0' ; printf(echoBuffer); } printf("\n"); close(sock); initialize TCP Server servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); echoServAddr.sin_port = htons(echoServPort); bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)); listen(servSock, MAXPENDING); for (;;){ clntLen = sizeof(echoClntAddr); clntSock = accept(servSock,(struct sockaddr *)&echoClntAddr, &clntLen); recvMsgSize = recv(clntSock, echoBuffer, RCVBUFSIZE, 0); while (recvMsgSize > 0){ send(clntSock, echoBuffer, recvMsgSize, 0); recvMsgSize = recv(clntSock, echoBuffer, RCVBUFSIZE, 0); } close(clntSock); } MPI #include <stdio.h> #include "mpi.h" printf("PROCS: %d, MYID: %d, MYVAL: %e\n", procs, myid, myval); MPI_Finalize(); return 0; } initialize 11 MPIの位置づけ Layer of MPI • ネットワークの違いを、MPIが隠ぺい Hide the differences of networks Applications MPI Sockets TCP … XTI UDP IP Ethernet driver, Ethernet card … … High-Speed Interconnect (InfiniBand, etc.) 12 MPIプログラムのコンパイル How to compile MPI programs • Compile command: mpicc Example) mpicc -O3 test.c -o test optimization option O is not 0 source file to compile executable file to create 13 MPIプログラムの実行 How to execute MPI programs • Prepare a script file Sample: #!/bin/sh #PBS -l nodes=2,walltime=00:01:00 #PBS -j oe #PBS -q p4 Number of Nodes (maximum: 4) Maximum Execution Time Store standard output and error in the same file. Name of Job Queue Commands to be Executed cd to the directory from where this job is submitted /usr/local/bin/mpiexec -f $PBS_NODEFILE -np 8 ./test-mpi cd $PBS_O_WORKDIR • Submit the script file qsub test.sh • Other commands Run MPI program with specified number (ex: 8) of processes • qstat (= check status), qdel job_number (= cancel job) 14 Ex 0) MPIプログラムの実行 Execution of an MPI program • まず、133.5.150.53 にログイン First of all, login to 133.5.150.53 • Windows: Use Putty • specify your private key • MacOS X: Use ssh command from terminal • specify your private key Ex 0) MPIプログラムの実行 Execution of an MPI program • ログイン後、以下を実行しなさい。 After login, try the following commands. $ cp /tmp/test-mpi.c . $ cp /tmp/test.dat . $ cp /tmp/test.sh . $ cat test-mpi.c $ cat test.dat $ mpicc test-mpi.c –o test-mpi $ qsub test.sh wait for a while $ ls (check the name of the result file (test.sh.o????)) $ less test.sh.o???? • 時間に余裕があったら,プロセス数を変えたり, プログラムを書き換えたりしてみる. Try changing the number of processes, or modifying the source program. MPIライブラリ MPI Library • MPI関数の実体は,MPIライブラリに格納されている The bodies of MPI functions are in "MPI Library". • mpicc が自動的に MPIライブラリをプログラムに結合する mpicc links the library to the program mpicc main() { MPI_Init(...); ... MPI_Comm_rank(...); ... MPI_Send(...); ... } source program compile link Executable file MPI_Init MPI_Comm_rank ... MPI Library 17 MPIプログラムの基本構造 Basic Structure of MPI Programs #include <stdio.h> #include "mpi.h" Crucial lines header file "mpi.h" int main(int argc, char *argv[]) { ... MPI_Init(&argc, &argv); Function for start-up ... MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &procs); ... MPI_Send(&val, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD); ... MPI_Recv(&myval, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status); You can call MPI functions in this area ... MPI_Finalize(); Functions for finish return 0; } 18 今日の MPI関数 MPI Functions Today • MPI_Init • Initialization • MPI_Finalize • Finalization • MPI_Comm_size • Get number of processes • MPI_Comm_rank • Get rank (= Process number) of this process • MPI_Send & MPI_Recv • Message Passing • MPI_Bcast & MPI_Gather • Collective Communication ( = Group Communication ) 19 MPI_Init Usage: int MPI_Init(int *argc, char **argv); • MPIの並列処理開始 Start parallel execution of in MPI • プロセスの起動やプロセス間通信路の確立等。 Start processes and establish connections among them. #include <stdio.h> • 他のMPI関数を呼ぶ前に、 #include "mpi.h" int main(int argc, char *argv[]) 必ずこの関数を呼ぶ。 { Most be called once before calling int myid, procs, ierr; otherMPI functions double myval, val; • 引数: Parameter: Example MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &procs); ... • main関数の2つの引数へのポインタを渡す。 Specify pointers of both of the arguments of 'main' function. • 各プロセス起動時に実行ファイル名やオプションを共有 するために参照。 Each process most share the name of the executable file, and the options given to the mpirun command. 20 20 MPI_Finalize Usage: int MPI_Finalize(); • 並列処理の終了 Finishes paralles execution • このルーチン実行後はMPIルーチンを 呼び出せない MPI functions cannot be called after this function. • プログラム終了前に全プロセスで必ずこのルーチンを実行させる。 Every process needs to call this function before exitting the program. Example main() { ... MPI_Finalize(); } 21 21 MPI_Comm_rank Usage: int MPI_Comm_rank(MPI_Comm comm, int *rank); • そのプロセスのランクを取得する Get the rank(= process number) of the process • 2番目の引数に格納 Returned in the second argument Example ... MPI_Comm_rank(MPI_COMM_WORLD, &myid); ... • 最初の引数 = “コミュニケータ” 1st argument = "communicator" • プロセスのグループを表す識別子 An identifier for the group of processes • 通常は,MPI_COMM_WORLD を指定 In most cases, just specify MPI_COMM_WORLD, here. • MPI_COMM_WORLD: 実行に参加する全プロセスによるグループ a group that consists all of the processes in this execution • プロセスを複数のグループに分けて、それぞれ別の仕事をさせることも可能 Processes can be devided into multiple groups and attached different jobs. 22 22 MPI_Comm_size • プロセス数を取得する Get the number of processes • 2番目の引数に格納される Usage: int MPI_Comm_size(MPI_Comm comm, int *size); Example ... MPI_Comm_size(MPI_COMM_WORLD, &procs); ... 23 23 一対一通信 Message Passing • 送信プロセスと受信プロセスの間で行われる通信 Communication between "sender" and "receiver" • 送信関数と受信関数を,"適切"に呼び出す. Functions of Sending and Receiving most be called in a correct manner. • "From" rank and "To" rank are correct • Specified size of the data to be transferred is the same on both side • Same "Tag" is specified on both side Rank 0 Send To: Rank 1 Size: 10 Integer data Tag: 100 Rank 1 Receive From: Rank 0 Size: 10 Integer data Tag: 100 Wait for the message 24 MPI_Send Usage: int MPI_Send(void *b, int c, MPI_Datatype d, int dest, int t, MPI_Comm comm); • 送信内容 Information of the message to send Example • start address of the data 開始アドレス, ... MPI_Send(&val, 1, MPI_DOUBLE, number of elements 要素数, MPI_COMM_WORLD); data type データ型, ... rank of the destination 送信先, tag, communicator (= MPI_COMM_WORLD, in most cases) • data types: Integer MPI_INT Real(Single) MPI_FLOAT Real(Double) MPI_DOUBLE Character MPI_CHAR i, 0, • tag: メッセージに付ける番号(整数) The number attached to each message • 不特定のプロセスから届く通信を処理するタイプのプログラムで使用 Used in a kind of programs that handles anonymous messages. • 通常は、0 を指定しておいて良い. Usually, you can specify 0. 25 25 Example of MPI_Send • 整数変数 d の値を送信(整数1個) Send the value of an integer variable 'd' MPI_Send(&d, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); • 実数配列 mat の最初の要素から100番目の要素までを送信 Send first 100 elements of array 'mat' (with MPI_DOUBLE type) MPI_Send(mat, 100, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD); • 整数配列 data の10番目の要素から50個を送信 Send elements of an integer array 'data' from 10th to 59th element MPI_Send(&(data[10]), 50, MPI_INT, 1, 0, MPI_COMM_WORLD); 26 MPI_Recv Usage: int MPI_Recv(void *b, int c, MPI_Datatype d, int src, int t, MPI_Comm comm, MPI_Status *st); • Information of the message to receive • start address for storing data 受信データ格納用の開始アドレス, Example number of elements 要素数, ... data type データ型, MPI_Recv(&myval, 1, MPI_DOUBLE, 0, 0, rank of the source 送信元, MPI_COMM_WORLD &status); ... tag (= 0, in most cases), communicator (= MPI_COMM_WORLD, in most cases), status • status: メッセージの情報を格納する整数配列 An integer array for storing the information of arrived message • 送信元ランクやタグの値を参照可能(通常は、あまり使わない) Consists the information about the source rank and the tag. ( Not be used in most case ) 27 27 集団通信 Collective Communications • グループ内の全プロセスで行う通信 Communications among all of the processes in the group • Examples) Rank 0 Rank 1 Rank 2 • MPI_Bcast • copy a data to other processes • MPI_Gather • Gather data from other processes to an array • MPI_Reduce • Apply a 'Reduction' operation to the distributed data to produce one array 3 1 8 2 3 1 8 2 Rank 0 3 1 8 2 Rank 1 7 5 Rank 2 9 7 5 9 Rank 0 Rank 1 1 2 3 12 15 4 5 6 Rank 2 7 8 9 18 28 MPI_Bcast Usage: int MPI_Bcast(void *b, int c, MPI_Datatype d, int root, MPI_Comm comm); • あるプロセスのデータを全プロセスにコピー copy a data on a process to all of the processes • Parameters: • start address, number of elements, data type, root rank, communicator • root rank: コピー元のデータを所有するプロセスのランク rank of the process that has the original data • Example: MPI_Bcast(a, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); Rank 0 a Rank 1 a Rank 2 a Rank 3 a 29 29 MPI_Gather Usage: int MPI_Gather(void *sb, int sc MPI_Datatype st, void *rb, int rc, MPI_Datatype rt, int root, MPI_Comm comm); • 全プロセスからデータを集めて一つの配列を構成 Gather data from other processes to construct an array • Parameters: • send data: start address, number of elements, data type, receive data: start address, number of elements, data type, (means only on the root rank) root rank, communicator • root rank: 結果の配列を格納するプロセスのランク rank of the process that stores the result array • Example: MPI_Gather(a, 3, MPI_DOUBLE, b, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); Rank 0 a Rank 1 a Rank 2 a Rank 3 a b 30 30 集団通信の利用に当たって Usage of Collective Communications • 同じ関数を全プロセスが実行するよう、記述する。 Every process must call the same function • 例えば MPI_Bcastは,root rankだけでなく全プロセスで実行 For example, MPI_Bcast must be called not only by the root rank but also all of the other ranks • 送信データと受信データの場所を別々に指定するタイプの集団通信で は、送信データの範囲と受信データの範囲が重ならないように指定す る。 On functions that require information of both send and receive, the specified ranges of the addresses for sending and receiving cannot be overlapped. • MPI_Gather, MPI_Allgather, MPI_Gatherv, MPI_Allgatherv, MPI_Recude, MPI_Allreduce, MPI_Alltoall, MPI_Alltoallv, etc. 31 まとめ Summary • MPIでは、一つのプログラムを複数のプロセスが実行する On MPI, multiple processes run the same program • 各プロセスには、そのランク(番号)に応じて仕事を割り当てる Jobs are attached according to the rank(the number) of each process • 各プロセスはそれぞれ自分だけの記憶空間で動作する Each process runs on its own memory space • 他のプロセスが持っているデータを参照するには、通信する Accesses to the data on other processes can be made only by explicit communication among processes • MPI functions • MPI_Init, MPI_Finalize, MPI_Comm_rank • MPI_Send, MPI_Recv • MPI_Bcast, MPI_Gather 32 References • MPI Forum http://www.mpi-forum.org/ • specification of "MPI standard" • MPI仕様(日本語訳) http://phase.hpcc.jp/phase/mpi-j/ml/ • 理化学研究所の講習会資料 http://accc.riken.jp/HPC/training/mpi/mpi_all_2007-02-07.pdf 33 33 Ex 1) 乱数を表示するプログラム A program that displays random numbers • 「各プロセスがそれぞれ自分のランクと整数乱数を一つ表示するプログ ラム」を作成しなさい。 Make a program in which each process displays its own rank with one integer random number • Sample: #include <stdio.h> #include <stdlib.h> #include <sys/time.h> int main(int argc, char *argv[]) { int r; struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_usec); r = rand(); printf("%d¥n", r); } Ex 1) (cont.) • Example of the result of execution 1: 0: 3: 2: 4: 5: 6: 7: 520391 947896500 1797525940 565917780 1618651506 274032293 1248787350 828046128 Ex 1) Sample of the answer #include #include #include #include <stdio.h> <stdlib.h> <sys/time.h> "mpi.h" int main(int argc, char *argv[]) { int r, myid, procs; struct timeval tv; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &procs); gettimeofday(&tv, NULL); srand(tv.tv_usec); r = rand(); printf("%d: %d¥n", myid, r); MPI_Finalize(); } 表示されるデータの順番がランクと一致しない The data is not printed out in the order of ranks. 課題: 順番をそろえて表示する Report: Display in order • Ex 1) で作成したプログラムについて、以下の条件を満たすように修正 しなさい。 「ランク0からランクの順に、それぞれのプロセスで生成した乱数を表 示する。」 Modify the program in Ex1), so that: Messages are printed out in the order of the rank of each process • Example of the result of the execution 0: 1: 2: 3: 4: 5: 6: 7: 1524394631 999094501 941763604 526956378 152374643 1138154117 1926814754 156004811 来週の講義で、2~3名の学生を指名し、 自分の回答を説明してもらいます。 2~3 students will be designated to show and explain their answer at the next class. Hint • 少なくとも 2つの方法が考えられる At least, two methods are possible. • Method 1) (Easy) • Gather the data to rank 0, first. • Then, let rank 0 to print data in order. • Method 2) (Little hard) • Before rank i prints its data, receive a message from rank i-1 (i > 0) • After rank i prints its data, send a message to rank i+1 (i<P-1) • P is the total number of processes. ともかく、講義資料のプログラム例を実行し、各行の意味を理解しましょう。 First of all, try sample programs in this material and understand the meanings, line by line. 38
© Copyright 2024 ExpyDoc