[[ノート>ノート/ノート]]~
訪問者数 &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数である。