以下の構造を持っています。ポインタを含む構造体のMPI_Datatypeの作成
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
私はMPI_Send
とMPI_Receive
を使用して、この構造を転送したいです。この構造のためにMPI_Datatype
を作成するにはどうすればよいですか?
以下の構造を持っています。ポインタを含む構造体のMPI_Datatypeの作成
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
私はMPI_Send
とMPI_Receive
を使用して、この構造を転送したいです。この構造のためにMPI_Datatype
を作成するにはどうすればよいですか?
別のマシンへのポインタの送信は無意味です(意図しない)。バーチャルアドレッシングのために、ポインタは受信側のマシン上の無効なメモリ位置を指している可能性があります。そうでない場合でも、ポインティングしていたデータを実際に送信していません。
しかし、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データ型がこれらの構造体の特定のインスタンスに固有であるため、それぞれのデータ型を定義してコミットする必要があります。
また、元の構造体を再作成する場合は、受信側で同様のトリッキーなアンパックを行う必要があることに注意してください。
助けてくれてありがとう。私はこれを試みましたが、それは方法についてのラウンドであり、非常に多くのデータ型を作成していました。だから私は代わりに私のデータ表現を変更しました。はい、ポインタは動的配列でした。 – ap040
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
フィールドにAi
とAx
の両方で配列の要素数を保存することを想定)のような何かをするのに十分な大きを割り当てます構造体を保持し、その中にメッセージを受け取り、逆の変換を行うことができるバッファ。
もう一度、MPI_Get_count
を使用してメッセージの長さから簡単に抽出できるので、実際の値はnz
です。
は、多くの場合、それは概念的にも優れてい
「を行うには賢明なことは、構造体の配列を使用するようにプログラムを変換することです」。
MPI_PackとMPI_Unpackを使用して、別のメカニズムを指摘したいと思います。たとえば、元の構造体では、最初の整数をパックし、2つの配列をパックすることができます。レシーバは整数をアンパックし、次に解凍する他の物の数を知ります。
オブジェクトに直接アクセスすることはできませんが、イテレータなどでしかアクセスできない場合にも、これは良い解決策です。
なぜMPIプロセス間でポインタを送信したいのですか?これらは、分散メモリシステムでは移植性がありません。 – talonmies