MPI では、MPI_Bcast
純粋に便利な関数ですか、それとも、すべてのランクをループして同じメッセージをすべてのランクに送信する代わりに、それを使用することの効率上の利点はありますか?
理由: MPI_Bcast
ルートを含む全員にメッセージを送信する の動作は、私にとっては不便なので、正当な理由がない限り使用しないか、ルートにメッセージを送信しないようにすることができます。
MPI では、MPI_Bcast
純粋に便利な関数ですか、それとも、すべてのランクをループして同じメッセージをすべてのランクに送信する代わりに、それを使用することの効率上の利点はありますか?
理由: MPI_Bcast
ルートを含む全員にメッセージを送信する の動作は、私にとっては不便なので、正当な理由がない限り使用しないか、ルートにメッセージを送信しないようにすることができます。
MPI_Bcast を使用すると、独自にロールするよりも確実に効率的になります。メッセージサイズや通信アーキテクチャなどの要因に基づいて集合操作を最適化するために、すべての MPI 実装で多くの作業が行われています。
たとえば、MPICH2 の MPI_Bcast は、メッセージのサイズに応じて異なるアルゴリズムを使用します。短いメッセージの場合、バイナリ ツリーを使用して、処理の負荷と待ち時間を最小限に抑えます。長いメッセージの場合、バイナリ ツリー スキャッタとそれに続くオールギャザーとして実装されます。
さらに、HPC ベンダーは、特に集合操作のために、基礎となる相互接続を効率的に使用する MPI 実装を提供することがよくあります。たとえば、ハードウェアでサポートされているマルチキャスト スキームを使用したり、既存の相互接続を利用できる特注のアルゴリズムを使用したりすることができます。
集合的なコミュニケーションは、自分で展開するよりもはるかに高速になる可能性があります。すべての MPI 実装は、これらのルーチンを高速化するために多くの時間を費やしています。
定期的に集合型のことを行いたいが、タスクのサブセットのみを行いたい場合は、おそらく独自のサブコミュニケーターを作成し、それらのコミュニケーターで BCAST などを使用することをお勧めします。
答えは、一般的なケースでは、MPI_Bcastはおそらくループよりも高速であるということです。一般に、MPI集合は、広範囲のメッセージサイズ、通信サイズ、および特定のランクレイアウトにわたって最適化されます。
とは言うものの、特定のメッセージサイズ、通信サイズ、ランクレイアウトで集合体を打ち負かすことができるかもしれません。たとえば、ノンブロッキングのポイントツーポイントコール(ISendやRecv / IRecvなど)のループは高速かもしれませんが、おそらくいくつかの特定のメッセージサイズ、通信サイズ、ランクレイアウトでのみです。
コーディングしている特定のアルゴリズムがBcastのパターンを必要とする場合(たとえば、すべてのランクがルートから同じデータペイロードを取得する場合)、Bcastコレクティブを使用します。一般に、独自の「集合的な置換」をロールすることによって複雑さを追加する価値はありません。
アルゴリズムに必要な他のメッセージパターンがあり、部分的な適合のみのBcastがある場合は、自分でロールする価値があるかもしれませんが、個人的にはそのバーをかなり高く設定しました。
MPI_Bcast
定義により、1 つのプロセス (「ルート」) から他のすべてのプロセスにメッセージを送信します。おそらく、すべてのプロセスをループするよりも少し高速になるでしょう。mpich2
たとえば、実装では二項ツリーを使用してメッセージを配信します。
MPI_COMM_WORLD にブロードキャストしたくないが、サブグループを定義したい場合は、次のように実行できます。
#include <stdio.h>
#include "mpi.h"
#define NPROCS 8
int main(int argc, char **argv)
{
int rank, new_rank, sendbuf, recvbuf,
ranks1[4]={0,1,2,3}, ranks2[4]={4,5,6,7};
MPI_Group orig_group, new_group;
MPI_Comm new_comm;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sendbuf = rank;
/* Extract the original group handle */
MPI_Comm_group(MPI_COMM_WORLD, &orig_group);
/* Divide tasks into two groups based on rank */
if (rank < NPROCS/2) {
MPI_Group_incl(orig_group, NPROCS/2, ranks1, &new_group);
} else {
MPI_Group_incl(orig_group, NPROCS/2, ranks2, &new_group);
}
/* Create new communicator and then perform some comm
* Here, MPI_Allreduce, but you can MPI_Bcast at will
*/
MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
MPI_Allreduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_SUM, new_comm);
MPI_Group_rank (new_group, &new_rank);
printf("rank= %d newrank= %d recvbuf= %d\n", rank, new_rank, recvbuf);
MPI_Finalize();
}
次のような出力が生成される可能性があります。
rank= 7 newrank= 3 recvbuf= 22
rank= 0 newrank= 0 recvbuf= 6
rank= 1 newrank= 1 recvbuf= 6
rank= 2 newrank= 2 recvbuf= 6
rank= 6 newrank= 2 recvbuf= 22
rank= 3 newrank= 3 recvbuf= 6
rank= 4 newrank= 0 recvbuf= 22
rank= 5 newrank= 1 recvbuf= 22