[[ノート>ノート/ノート]]~
訪問者数 &counter();      最終更新 &lastmod();

**Fedora10でMPICH2 [#t9965123]
***09/02/06〜12 インストール周り [#c568624b]
-mpich2-1.0.8をインストール~
-[[インストールマニュアル:http://www.mcs.anl.gov/research/projects/mpich2/documentation/files/mpich2-1.0.8-installguide.pdf]]
-LiveCDからのインストール直後だと、結構いろいろなものが足りなかった。極端にはgccとかがない? 基本的にyumでインストールできる。
-インストールマニュアルのチェック項目で確認。~
mpdcheck でクライアント側からサーバーが見えない。 ⇒ 原因はiptables(ファイヤウォール)だった~
   ファイヤウォールが原因であるとの確認 〜 ファイヤウォールを止めてからmpdcheckでテストしたらうまく行った。だからファイヤウォールが原因。~
     /etc/init.d/iptables stop で止めて確認すればよい。~
   ファイヤウォールをとめたまま運用するわけに行かないので、iptablesは直ちに再起動。~
それで、iptablesの設定(ファイヤウォールの穴あけ)が必要。mpich2で使うホストのIPアドレスを決め打ちで、そこから発信されたエフェメラルポート着のtcpの通信を許可。~
iptablesのコマンドや設定法はあちこちのページ(たとえばhttp://penguin.nakayosi.jp/linux/iptables.htmlやhttp://itpro.nikkeibp.co.jp/article/COLUMN/20070327/266505/、マニュアルはhttp://www.linux.or.jp/JM/html/iptables/man8/iptables.8.html)に落ちている。~
修正したテーブルをセーブ(/etc/init.d/iptables save)しないと、次にシステム起動したときに戻ってしまうので注意。

-インストール(configure)のオプションで、--with-device=ch3:ssm を採用。
-おまけ: [[Optimizing Threaded MPI Execution on SMP Clusters:http://www.cs.ucsb.edu/projects/tmpi/ics01.ppt]]
-おまけ: [[mpich のデバッグ機能:http://www.alde.co.jp/information/mpich/debug.html]]

***09/02/12 使い方とテスト [#e53dd3ed]
-マニュアル: MPICH2添付のファイルを参照(コピーをローカルマシン上においてある)。~
  [[インストールマニュアルPDFファイル:http://oregano.yy.is.sci.toho-u.ac.jp/mpich2/install.pdf]]~
  [[ユーザーズマニュアルPDFファイル:http://oregano.yy.is.sci.toho-u.ac.jp/mpich2/user.pdf]]~
  [[Web版各コマンドのマニュアル:http://oregano.yy.is.sci.toho-u.ac.jp/mpich2]]

-MPI向けのC言語プログラミング
-MPI向けのC言語コンパイル:
 mpicc -o xxxx xxxx.c
⇒ xxxx.cをコンパイルし、実行形式ファイル xxxx を出力(生成)~
     (注)数学関数などを使うときは -lm などを忘れないこと~
     (注)適宜 Makefile などを作って活用するほうがいい(毎回忘れない)~

-.mpd.hostsファイルの作成(設定)~
MPICH2で使うホストの名前を、ファイル ".mpd.hosts"として作っておく必要がある。~
ここの例では、ホスト1つにしていて、
 oregano.yy.is.sci.toho-u.ac.jp:8
と書いておく。最後の8は最大プロセス数(=並列度)が8という意味。~
~
もう1つ、.mpd.confファイルが必要。これは別ホスト上で並列をするときの認証のパスワードらしく、($HOME)/.mpd.conf にファイルを置く。内容は secretword=******というもの。

-コマンド mpd --ncpus=8 を実行
--これによって、各ホスト上でサーバーmpdを起動。mpdはユーザ権限のままでよい~
    (注)--ncpus=8は、この1台のホスト上の最大プロセス数を8にするという意味らしい。

-プログラム xxxx を、mpiexec コマンドで実行
 mpiexec -n 8 ./xxxx
パラメタ -n 8 は、「8並列で」の意味。~
起動するプログラムは、(MPIでなくて普通なら)./xxxx として起動するところを、mpiexecにて起動。~
./はそのディレクトリに実行パスが通っていないので付けた。もし通っていれば不要。~
  (注)実行パスを通すには、bashでは~/.bash_profileあたりに書いておくとよい。
 PATH=$PATH:/usr/local/bin:./
     などとする。$PATH(元々入っているパス)に、/usr/local/binや./を追加したものをPATHに設定。

***ためしてみよう。 [#cf4a5ca4]
プログラム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つがこれらのメッセージを返す。

***では数値積分の例 [#xb8d8e62]
プログラムは
 #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数である。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS