C++でMPIを使ってノンブロッキング通信をする

MPIを使ってみました。
自分のパソコンは複数ノードないのでopenmpで十分な気もしますが。
簡単にまとめると
MPI:プログラムを複数プロセスで並列化する。並列する際にメモリは共有されない
Openmp:プロセスを複数スレッドに分けて並列化する。メモリは共有する

例えば1ノード4コアで4ノードあるとします。全部で16コアあるので、もし8プロセスで並列化した場合は1プロセスあたり2コアが割り当てられます。もし、openmpで1プロセス2スレッドで並列化した場合は結局1スレッド1コア使えることになります。1スレッドあたりのコアが1未満だったらどうなるのかはよく知りません。

statusはMPI_SOURCE, MPI_TAG, MPI_ERRORからなる構造体で stat.Get_source(); stat.Set_source(); stat.Get_tag(); stat.Set_tag(); stat.Get_error(); stat.Set_error();で取得できるみたいですが、Irecvを使ったときはget_source()を使っても-1になってしまい、うまくいきませんでした。

0~12000を3分割して各プロセスで和を求め、rank=0のプロセスに送信するプログラムです。
#include<iostream>
#include<mpi.h>
using namespace std;

int sum(int a, int b) {
int x = 0;
for (int i = a; i < b; i++) {
x += i;
}
return x;
}

int main(int argc, char** argv) {
MPI::Init(argc, argv);
int n = 12000;
int size, num, myid, x;
int tag = 1;
size = MPI::COMM_WORLD.Get_size();
myid = MPI::COMM_WORLD.Get_rank();
MPI::Status* st = new MPI::Status[size];
MPI::Request* req = new MPI::Request[size];
num = n / size;
if (myid == 0) {
//   statusのエラーを1にする
for (int i = 0; i < size - 1; i++) {
st[i].Set_error(1);
cout << "myid="<<i<<" error before " << st[i].Get_error() << endl;
}
int* buf = new int[size];
x= sum(0, num);
cout << "myid=" << myid << " x=" << x << endl;
buf[myid] = x;
//   各プロセスから結果を受信し、配列bufに格納
for (int i = 1; i < size; i++) {
req[i-1] = MPI::COMM_WORLD.Irecv(buf + i, 1, MPI::INT, i, tag);
}
//   waitする前にtestallを試す
cout << "recv flag before "<<req[0].Testall(size-1,req)<<endl;
req[0].Waitall(size - 1, req, st);
cout << "recv flag after " << req[0].Testall(size - 1, req) << endl;
//   statusのエラーが0になっているか確認
for (int i = 0; i < size - 1; i++) {
cout << "myid=" << i << " error after "  << st[i].Get_error() << endl;
}
//   bufの結果を確認
cout << "result " << endl;
for (int i = 0; i < size; i++) {
cout << "buf" << i << "=" << buf[i] << endl;
}
}
else {
if (myid != size - 1) {
x = sum(num*myid, (myid + 1)*num);
cout << "myid=" << myid << " x=" << x << endl;
req[myid - 1] = MPI::COMM_WORLD.Isend(&x,1, MPI::INT, 0, tag);
}
else {
x = sum(num*(size-1), n+1);
cout << "myid=" << myid << " x=" << x << endl;
req[myid - 1] = MPI::COMM_WORLD.Isend(&x, 1, MPI::INT, 0, tag);
}
req[0].Waitall(size - 1, req, st);
}
MPI::Finalize();
return 0;
}

実行結果
 mpic++ ex.cpp
 mpirun -np 3 ./a.out

myid=0 error before 1
myid=1 error before 1
myid=0 x=7998000
myid=1 x=23998000
myid=2 x=40010000
recv flag before 0
recv flag after 1
myid=0 error after 0
myid=1 error after 0
result
buf0=7998000
buf1=23998000
buf2=40010000

0 件のコメント:

コメントを投稿

AtCoder Beginner Contest 044 C - 高橋君とカード / Tak and Cards

https://beta.atcoder.jp/contests/abc044/tasks/arc060_a すべてのカードからaを引く 平均がa⇔和がa になる mapを使って各カードが何枚ずつ有るか記録する。 カードがn種類あるとすると、 0<=i...