2012-05-02 12 views
10

以下の構造を持っています。ポインタを含む構造体のMPI_Datatypeの作成

typedef struct 
{ 
int *Ai; 
double *Ax; 
int nz; 
}column; 

私はMPI_SendMPI_Receiveを使用して、この構造を転送したいです。この構造のためにMPI_Datatypeを作成するにはどうすればよいですか?

+0

なぜMPIプロセス間でポインタを送信したいのですか?これらは、分散メモリシステムでは移植性がありません。 – talonmies

答えて

8

別のマシンへのポインタの送信は無意味です(意図しない)。バーチャルアドレッシングのために、ポインタは受信側のマシン上の無効なメモリ位置を指している可能性があります。そうでない場合でも、ポインティングしていたデータを実際に送信していません。

しかし、MPI_Address()MPI_Hindexedデータ型を適切に使用すると、データのメモリレイアウトを記述することができます(ポインタが動的配列を指していることを前提としています)。例えば。 MPI_Address()を使用して取得したオフセットで、3 MPI_INT秒、5秒MPI_DOUBLE、および1 MPI_INT:5 double秒に3つのint sのAiポイント、およびAxポイントならば、あなたは3つのブロックでHindexedタイプが必要になります。

送信する項目の数を変更したり、配列を完全に再割り当てすると、データ型を再定義して再設定することを忘れないでください。また、複数の構造体を送信する場合は、MPIデータ型がこれらの構造体の特定のインスタンスに固有であるため、それぞれのデータ型を定義してコミットする必要があります。

また、元の構造体を再作成する場合は、受信側で同様のトリッキーなアンパックを行う必要があることに注意してください。

+0

助けてくれてありがとう。私はこれを試みましたが、それは方法についてのラウンドであり、非常に多くのデータ型を作成していました。だから私は代わりに私のデータ表現を変更しました。はい、ポインタは動的配列でした。 – ap040

9

MPIは、配列の構造ではなく、構造の配列で動作するように設計されています。

MPI_Hindexed @suszterpattが提案したのはひどいハックです。構造体タイプの1つの要素と、MPIデータ型の定義に使用された要素のみを送信することができます。同じ構造タイプの他の変数については、計算されたオフセットが間違っていることがほとんど保証されています。 Hindexedの型は、すべての要素に同じMPIデータ型を使用するため、intとdoublesの両方を送信することはできません。

行うには賢明なことは、構造体の配列を使用するようにプログラムを変換することです:

typedef struct 
{ 
    int i; 
    double z; 
} point; 

typedef struct 
{ 
    point *A; 
    int nz; 
} column; 

今ではMPI構造型point_typeを作成し、としてcolumn.Aを与えて、そのタイプのnz要素を送信するためにそれを使用することができますバッファアドレス:

int lens[3]; 
MPI_Aint base, disps[2]; 
MPI_Datatype oldtypes[2], point_struct, point_type; 

MPI_Get_address(&point, disps); 
MPI_Get_address(&point.z, disps+1); 
base = disps[0]; 

lens[0] = 1; disps[0] = MPI_Aint_diff(disps[0], base); oldtypes[0] = MPI_INT; 
lens[1] = 1; disps[1] = MPI_Aint_diff(disps[1], base); oldtypes[1] = MPI_DOUBLE; 
MPI_Type_create_struct(2, lens, disps, oldtypes, &point_struct); 
MPI_Type_create_resized(point_struct, 0, sizeof(point), &point_type); 
MPI_Type_commit(&point_type); 

MPI_Send(column.A, column.nz, point_type, ...); 

これは、最初の構造体のメンバのレイアウトを記述するMPIデータ型point_structを作成しますが、専用のパディングを考慮していませんしたがって、そのような構造のアレイを確実に送信するために使用することはできません。したがって、正確なエクステントを持つ第2のデータ型point_typeは、MPI_Type_create_resizedを使用して作成されます。

もし、 MPI_ProbeでメッセージをPEEK(すなわち直線 nzフィールドに行く) point_typeの種類と MPI_Get_countで要素の数を抽出し、 Aフィールドを割り当て、受信するために MPI_Recvでそれを使用する受信側で

nz要素:

MPI_Status status; 
MPI_Probe(source, tag, comm, &status); 
MPI_Get_count(&status, point_type, &column.nz); 
if (nz == MPI_UNDEFINED) 
    ... non-integral message was received, do something 
column.A = (point *)malloc(column.nz*sizeof(point)); 
MPI_Recv(column.A, column.nz, point_type, source, tag, comm, MPI_STATUS_IGNORE); 

そのコードの変更は、あなたはまだ、通常をマーシャリング(未)と呼ばれるプロセスを、それを送信する前に、あなたの構造を転換する中間段階を経ることができますことは不可能である場合。あなたが逆の作業を行う必要があり、受信側では

point *temp = (point *)malloc(nz*sizeof(point)); 
for (int i = 0; i < column.nz; i++) 
{ 
    temp[i].i = column.Ai[i]; 
    temp[i].z = column.Az[i]; 
} 
MPI_Send(temp, nz, point_type, ...); 
free(temp); 

:あなたのケースでは、この(私はあなたがnzフィールドにAiAxの両方で配列の要素数を保存することを想定)のような何かをするのに十分な大きを割り当てます構造体を保持し、その中にメッセージを受け取り、逆の変換を行うことができるバッファ。

もう一度、MPI_Get_countを使用してメッセージの長さから簡単に抽出できるので、実際の値はnzです。

+0

+1これは非常に有益です – pyCthon

+0

ありがとう、これは役に立ちました。あなたが提案したような中間表現を使用しましたが、それははるかに優れていました。 – ap040

+0

あなたは "disp [0]"について本当ですか?ゼロ要素が文字の場合、最小の整列単位の左または右のバイトかどうかはわかりません。言い換えれば、私はそのオフセットを明示的に計算します。 –

1

は、多くの場合、それは概念的にも優れてい

「を行うには賢明なことは、構造体の配列を使用するようにプログラムを変換することです」。

MPI_PackとMPI_Unpackを使用して、別のメカニズムを指摘したいと思います。たとえば、元の構造体では、最初の整数をパックし、2つの配列をパックすることができます。レシーバは整数をアンパックし、次に解凍する他の物の数を知ります。

オブジェクトに直接アクセスすることはできませんが、イテレータなどでしかアクセスできない場合にも、これは良い解決策です。

関連する問題