ここでは、ポイントツーポイントとコレクティブの両方を使用する作業用コードを示します(集合バージョンは以下にコメントアウトされていますが正常に動作します)。マスター側の受信側の非連続データに対応するベクトルタイプを定義する必要があります。コレクティブギャザーを使用するには、このベクトルのサイズを混乱させて、ギャザーバージョンを使用する必要があります。
配列インデックスが乱雑になるのは簡単です。一般的には、6x12マトリックス上に2x3配列のプロセスを使用していますので、故意に正方形ではありません。
私はタブ/スペースの問題を抱えているようですが、私は本当に将来これを整理しなければなりません!
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define M 6
#define N 12
#define MP 2
#define NP 3
#define MLOCAL (M/MP)
#define NLOCAL (N/NP)
#define TAG 0
int main(void)
{
int master[M][N];
int local[MLOCAL][NLOCAL];
MPI_Comm comm = MPI_COMM_WORLD;
int rank, size, src;
int i, j;
int istart, jstart;
int displs[MP*NP], counts[MP*NP];
MPI_Status status;
MPI_Request request;
MPI_Datatype block, blockresized;
MPI_Init(NULL, NULL);
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
if (size != MP*NP)
{
if (rank == 0) printf("Size %d not equal to MP*NP = %d\n", size, MP*NP);
MPI_Finalize();
return 1;
}
for (i=0; i < M; i++)
{
for (j=0; j < N; j++)
{
master[i][j] = rank;
}
}
for (i=0; i < MLOCAL; i++)
{
for (j=0; j < NLOCAL; j++)
{
local[i][j] = rank+1;
}
}
// Define vector type appropriate for subsections of master array
MPI_Type_vector(MLOCAL, NLOCAL, N, MPI_INT, &block);
MPI_Type_commit(&block);
// Non-blocking send to avoid deadlock with rank 0 sending to itself
MPI_Isend(local, MLOCAL*NLOCAL, MPI_INTEGER, 0, TAG, comm, &request);
// Receive from all the workers
if (rank == 0)
{
for (src=0; src < size; src++)
{
// Find out where this block should go
istart = (src/NP) * MLOCAL;
jstart = (src%NP) * NLOCAL;
// receive a single block
MPI_Recv(&master[istart][jstart], 1, block, src, TAG, comm, &status);
}
}
// Wait for send to complete
MPI_Wait(&request, &status);
/* comment out collective
// Using collectives -- currently commented out!
MPI_Type_create_resized(block, 0, sizeof(int), &blockresized);
MPI_Type_commit(&blockresized);
// Work out displacements in master in counts of integers
for (src=0; src < size; src++)
{
istart = (src/NP) * MLOCAL;
jstart = (src%NP) * NLOCAL;
displs[src] = istart*N + jstart;
counts[src] = 1;
}
// Call collective
MPI_Gatherv(local, MLOCAL*NLOCAL, MPI_INT,
master, counts, displs, blockresized,
0, comm);
*/
// Print out
if (rank == 0)
{
for (i=0; i < M; i++)
{
for (j=0; j < N; j++)
{
printf("%d ", master[i][j]);
}
printf("\n");
}
}
MPI_Finalize();
}
6つのプロセスでOK動作するようです:
mpiexec -n 6 ./arraygather
1 1 1 1 2 2 2 2 3 3 3 3
1 1 1 1 2 2 2 2 3 3 3 3
1 1 1 1 2 2 2 2 3 3 3 3
4 4 4 4 5 5 5 5 6 6 6 6
4 4 4 4 5 5 5 5 6 6 6 6
4 4 4 4 5 5 5 5 6 6 6 6
これは、マトリックスは、プロセスグリッド上に正確に分解するどのような状況で動作するはずです。プロセスがすべてサブ行列のサイズがまったく同じでない場合は、少し複雑になります。
ここで探している回答を見つけることができます:http://stackoverflow.com/questions/9269399/sending-blocks-of-2d-array-in-c-using-mpi – Angelos