私は次のような構造をしています。
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
MPI_Send
とを使用してこの構造を転送したいと思いMPI_Receive
ます。MPI_Datatype
この構造のを作成するにはどうすればよいですか?
MPIは、配列の構造ではなく、構造の配列で機能するように設計されています。
@suszterpattMPI_Hindexed
が提案したのはひどいハックです。構造タイプの1つの要素と、MPIデータ型の定義に使用された要素のみを送信できます。同じ構造タイプの他の変数の場合、計算されたオフセットが間違っていることがほとんど保証されます。Hindexed型に加えて、すべての要素に1つの同じMPIデータ型を使用するため、intとdoubleの両方を送信することはできません。
賢明なことは、構造体の配列を使用するようにプログラムを変換することです。
typedef struct
{
int i;
double z;
} point;
typedef struct
{
point *A;
int nz;
} column;
これで、MPI構造化タイプを作成し、それを使用して、バッファーアドレスとして指定するそのタイプの要素point_type
を送信できます。nz
column.A
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
されますが、最後にパディングが考慮されないため、このような構造体の配列を確実に送信するために使用することはできません。したがって、point_type
を使用して、正しい範囲の2番目のデータ型が作成されMPI_Type_create_resized
ます。
受信者側では、でメッセージをのぞき、タイプ(フィールドに直接行く)MPI_Probe
で要素の数を抽出し、フィールドを割り当て、それを使用して要素を受信します。MPI_Get_count
point_type
nz
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);
そのコード変更が不可能な場合でも、構造を送信する前に構造を変換する中間ステップを実行できます。このプロセスは通常、(非)マーシャリングと呼ばれます。あなたの場合、次のようなことをします(配列要素の数を両方Ai
とフィールドAx
に格納すると仮定しますnz
):
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
繰り返しになりますが、の実際の値は、を使用してメッセージの長さから簡単に抽出できるため、送信する必要はありませんMPI_Get_count
。
別のマシンにポインターを送信しても意味がありません (しゃれは意図されていません)。仮想アドレッシングのため、ポインターは受信側マシンの無効なメモリ位置を指している可能性が高く、そうでない場合でも、ポインターが指していたデータを実際に送信していません。
ただし、データ型を適切に使用すればMPI_Address()
、MPI_Hindexed
データのメモリ レイアウトを記述することができます (ポインタが動的配列を指していると想定しています)。たとえば、Ai
が 3int
をAx
指し、 5を指している場合、 を使用して取得したオフセットを持つ、 3 、 5 、および 1 の3 つのブロックをdouble
持つ型が必要になります。Hindexed
MPI_INT
MPI_DOUBLE
MPI_INT
MPI_Address()
送信するアイテムの数を変更したり、配列全体を再割り当てしたりする場合は、データ型を再定義して再コミットすることを忘れないでください。また、複数の構造体を送信する場合は、MPI データ型がこれらの構造体の 1 つの特定のインスタンスに固有であるため、それぞれに対してこのデータ型を定義してコミットする必要があります。
また、元の構造体を再作成する場合は、受信側で同様にトリッキーなアンパックを行う必要があることに注意してください。