MPIのMPI_Allgather関数とMPI_Alltoall関数の主な違いは何ですか?
つまり、MPI_Allgatherが役立ち、MPI_Alltoallが役に立たない例を誰かが私に与えることができるということですか?およびその逆。
主な違いが理解できませんか?どちらの場合も、すべてのプロセスがコミュニケーターに参加している他のすべてのプロセスにsend_cnt要素を送信して受信するように見えますか?
ありがとうございました
画像には1000を超える単語が含まれているため、ここにいくつかのASCIIアート画像があります。
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Allgather a,b,c,A,B,C,#,@,%
1 A,B,C ----------------> a,b,c,A,B,C,#,@,%
2 #,@,% a,b,c,A,B,C,#,@,%
これは通常のMPI_Gather
であり、この場合にのみ、すべてのプロセスがデータチャンクを受信します。つまり、操作にはルートがありません。
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Alltoall a,A,#
1 A,B,C ----------------> b,B,@
2 #,@,% c,C,%
(a more elaborate case with two elements per process)
rank send buf recv buf
---- -------- --------
0 a,b,c,d,e,f MPI_Alltoall a,b,A,B,#,@
1 A,B,C,D,E,F ----------------> c,d,C,D,%,$
2 #,@,%,$,&,* e,f,E,F,&,*
(各要素が送信元のランクで色分けされていると見栄えがよくなりますが...)
MPI_Alltoall
はMPI_Scatter
とMPI_Gather
の組み合わせとして機能します-各プロセスの送信バッファはMPI_Scatter
のように分割され、チャンクの各列はそれぞれのプロセスによってランク付けされます。チャンク列の番号と一致します。 MPI_Alltoall
は、データのチャンクに作用するグローバル転置操作と見なすこともできます。
2つの操作を交換できる場合はありますか?この質問に適切に回答するには、送信バッファ内のデータと受信バッファ内のデータのサイズを分析する必要があります。
operation send buf size recv buf size
--------- ------------- -------------
MPI_Allgather sendcnt n_procs * sendcnt
MPI_Alltoall n_procs * sendcnt n_procs * sendcnt
受信バッファサイズは実際にはn_procs * recvcnt
ですが、MPIは、送信される基本要素の数が受信される基本要素の数と等しくなければならないことを要求します。したがって、同じ場合MPIデータ型はMPI_All...
の送信部分と受信部分の両方で使用され、recvcnt
はsendcnt
と等しくなければなりません。
同じサイズの受信データに対して、各プロセスによって送信されるデータの量が異なることはすぐにわかります。 2つの操作が等しい場合、1つの必要条件は、両方のケースで送信されたバッファーのサイズが等しい、つまりn_procs * sendcnt == sendcnt
であるということです。これは、n_procs == 1
、つまりプロセスが1つしかない場合にのみ可能です。 、またはsendcnt == 0
の場合、つまりデータがまったく送信されていません。したがって、両方の操作が実際に交換可能であるという実際的に実行可能なケースはありません。しかし、送信バッファ内の同じデータをMPI_Allgather
倍に繰り返すことにより、MPI_Alltoall
をn_procs
でシミュレートできます(すでにTyler Gillによって指摘されています)。次に、1つの要素の送信バッファを使用したMPI_Allgather
のアクションを示します。
rank send buf recv buf
---- -------- --------
0 a MPI_Allgather a,A,#
1 A ----------------> a,A,#
2 # a,A,#
そして、ここで同じものがMPI_Alltoall
で実装されました:
rank send buf recv buf
---- -------- --------
0 a,a,a MPI_Alltoall a,A,#
1 A,A,A ----------------> a,A,#
2 #,#,# a,A,#
逆は不可能です-一般的な場合、MPI_Alltoall
をMPI_Allgather
でシミュレートすることはできません。
これらの2つの方法は確かに非常に似ていますが、2つの方法の間に1つの重要な違いがあるようです。
MPI_Allgatherは、各プロセスの受信バッファーにまったく同じデータがあることで終了し、各プロセスは配列全体に1つの値を提供します。たとえば、一連のプロセスのそれぞれが状態に関する単一の値を他のすべての人と共有する必要がある場合、それぞれが単一の値を提供します。これらの値はすべてのユーザーに送信されるため、すべてのユーザーが同じ構造のコピーを持つことになります。
MPI_Alltoallは、他のプロセスに同じ値を送信しません。他のプロセスと共有する必要がある単一の値を提供する代わりに、各プロセスは、他のプロセスに与える1つの値を指定します。つまり、n個のプロセスでは、それぞれが共有するn個の値を指定する必要があります。次に、各プロセッサーjについて、そのk番目の値が送信され、受信バッファー内のk番目のj番目のインデックスを処理します。これは、各プロセスに他のプロセスごとに1つの一意のメッセージがある場合に役立ちます。
最後に、allgatherとalltoallを実行した結果は、各プロセスが送信バッファーを同じ値で満たした場合と同じになります。唯一の違いは、オールギャザーの方がはるかに効率的であることです。