![]() |
ノート/Fedora10でMPICH2http://pepper.is.sci.toho-u.ac.jp/pepper/index.php?%A5%CE%A1%BC%A5%C8%2FFedora10%A4%C7MPICH2 |
![]() |
ノート
訪問者数 4844 最終更新 2009-02-15 (日) 17:43:43
mpicc -o xxxx xxxx.c⇒ xxxx.cをコンパイルし、実行形式ファイル xxxx を出力(生成)
oregano.yy.is.sci.toho-u.ac.jp:8と書いておく。最後の8は最大プロセス数(=並列度)が8という意味。
mpiexec -n 8 ./xxxxパラメタ -n 8 は、「8並列で」の意味。
PATH=$PATH:/usr/local/bin:./などとする。$PATH(元々入っているパス)に、/usr/local/binや./を追加したものをPATHに設定。
プログラム1 hello.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "mpi.h" #define MSG_LEN 100 int main(int argc, char* argv[]){ int my_rank; int tag = 0; char message[MSG_LEN]; /* 全てのMPI関数を呼び出す前に一回だけ呼び出す */ MPI_Init(&argc, &argv); /* 自分のランクを調べる */ MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /* ランク毎に処理を分岐 */ /* ランク0以外のプロセスの処理 */ if(my_rank != 0){ int dest = 0; /* 送信先 */ sprintf(message, "Hello, my process rank is %d", my_rank); /* ランク0のプロセスにメッセージ送信 */ MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); } /* ランク0のプロセスの処理 */ else{ int process_num; /* プロセス数 */ int source; /* 送信元 */ MPI_Status recv_status; /* 受信時のステータス */ /* プロセス数を調べる */ MPI_Comm_size(MPI_COMM_WORLD, &process_num); for(source = 1; source < process_num; source++){ /* ランク1〜process_numのプロセスからメッセージを受信 */ MPI_Recv(message, MSG_LEN, MPI_CHAR, source, tag, MPI_COMM_WORLD, &recv_status); fprintf(stdout, "%s\n", message); } } /* MPI関数を呼び出した後,最後に一回だけ呼び出す */ MPI_Finalize(); exit(EXIT_SUCCESS); }
では、これをコンパイルすると
mpicc -o hello hello.c
エラーメッセージは無く、ファイルhelloができる。
次に実行してみよう。まずmpd --ncpus=8 でmpdサーバー(デーモン)を起動する。
mpd --ncpus=8 &
何もメッセージなし。エラーなく起動したらしい。では並列実行開始。
$ mpiexec -n 8 hello Hello, my process rank is 1 Hello, my process rank is 2 Hello, my process rank is 3 Hello, my process rank is 4 Hello, my process rank is 5 Hello, my process rank is 6 Hello, my process rank is 7
1行目: mpiexecで並列起動。-n 8で8並列を指定。ホストoreganoは8並列まで可能。
実行するプログラムは hello 。このディレクトリには実行パスが通っているので、./はさぼった。
2行目以降: 実行結果。1つのCPUがマスターとなり、残り7つがこれらのメッセージを返す。
プログラムは
#include <stdio.h> #include <math.h> #include "mpi.h" //#define DIV_NUM 160000 /* 全体の閾値の分割数 */ #define DIV_NUM 160000000 /* 全体の閾値の分割数 */ int main(int argc, char* argv[]) { int div_num = DIV_NUM; int my_rank; int tag = 0; int dest; /* 送信先 */ int process_num; /* プロセス数 */ int source; /* 送信元 */ int i; double time1,time2; /* 実行時間測定用変数 */ int start_i; /* プロセッサ毎の閾値の最小値 */ int end_i; /* プロセッサ毎の閾値の最大値 */ int block_size; /* プロセッサ毎のストリップ数 */ double x; MPI_Status status; double h,pi,s,S=0.0; double my_x; int my_i, my_maxi=100000000; /* 全てのMPI関数を呼び出す前に一回だけ呼び出す */ MPI_Init(&argc, &argv); time1 = MPI_Wtime(); /* 自分のランクを調べる */ MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); /* プロセス数を調べる */ MPI_Comm_size(MPI_COMM_WORLD, &process_num); /* ランク0以外の処理 */ if(my_rank != 0) { dest = 0; /* プロセス毎の閾値の算出 */ block_size = DIV_NUM/(process_num-1); start_i = block_size * (my_rank-1); end_i = start_i + block_size -1; if (my_rank == process_num-1) { end_i = DIV_NUM; } //printf("my_rank:%d start_i:%d end_i:%d\n", my_rank, start_i, end_i); /* 積分の計算 */ s = 0.0; h = 1.0/((double) DIV_NUM); for(i=start_i; i<=end_i; i++) { x = h * ((double) i); s = s + sqrt(1.0 - (x*x)); } //printf("%f\n",s); /* ランク0にメッセージを送信 */ MPI_Send(&s, 1, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD); } /* ランク0の処理 */ else { //printf("DIV_NUM:%d process_num:%d block_size:%d\n",DIV_NUM,process_num, DIV_NUM/(process_num-1)); /* 他のプロセスからメッセージを受け取る */ for(source = 1; source < process_num; source++) { MPI_Recv(&s, 1, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, &status); S += s; } h = 1.0/((double) DIV_NUM); pi = (S - 0.5) * h * 4.0; /* 面積から円周率を計算 */ /* 積分結果の印刷 */ printf("N = %d, S = %.20f, pi = %.20f\n",DIV_NUM,S,pi); /* 時間表示 */ time2 = MPI_Wtime(); printf("time = %e seconds\n",time2 - time1); } /* MPI関数を呼び出した後、最後に1回だけ呼び出す */ MPI_Finalize(); }
原理は、1つのCPUをマスターに、残りを計算に割当てる。計算CPUは全体でDIV_NUM個のストリップ(台形)のうち、左から自分のプロセッサ番号番目の場所の面積計算を行う。マスターは最後に計算CPUから結果を受信して、足し合わせる。
分割のつくりはなるべく整数によった。右端は1/DIV_NUMが割り切れないことを考えて、端の値に強制した。幅hの掛け算はすべて総和を計算してから行った。また、台形法では両端は1/2回ずつでよいのだが、変な条件を付けずすべてのプロセッサで同じに計算しておいて、最後に両端の1/2分を引いた。具体的には左端の関数値1.0の1/2の0.5を引いた。右端は関数値が0なので引かなくてよい。
結果は次のようになった。
mpiexec -n 8 pi_MPI_090215 N = 160000000, S = 125663706.64357584714889526367, pi = 3.14159265358939610024 time = 1.039691e+00 seconds
mpiexec -n 2 pi_MPI_090215 N = 160000000, S = 125663706.64357669651508331299, pi = 3.14159265358941741653 time = 7.150658e+00 seconds
計算結果は、3.141592653589 で次の桁が3や4である。また、時間とCPU数の関係は、
CPU数 2(1) 3(2) 5(4) 8(7) 時間 7.15 3.58 1.79 1.04
但しCPU数は、カッコ無が全CPU数、カッコ内が計算CPU数である。