如何使用MPI发送3D阵列的切片?

时间:2019-08-19 23:03:37

标签: c++ mpi

我有一个3D数组Foo3D(50 x 100 x 100),其秩为0和1。Foo3D的分配方式如下:

int nx = 50;
int ny = 100;
int nz = 100;
typedef int nRarray[100][50];
nRarray *Foo3D;
if ((Foo3D = (nRarray *)malloc((nx*ny*nz)*sizeof(int))) == 0) {fprintf(stderr,"malloc1 Fail \n"); return 1;}

我为等级0的Foo3D分配了一些数字,并将其保存为新的2D数组(Foo2D)如下:

if (myrank == 0) {
for (int j = 0; j < ny; j++) {
 for (int k = 0; k < nz; k++) {

   Foo3D[0][j][k] = j + k;
   Foo2D[j][k] = Foo3D[0][j][k];
}
 } 
}

现在,我想发送Foo2D到排名1,并将其放在Foo3D中的位置。事实上,我知道我可以将Foo2D发送到排名1的位置:

if (myrank == 0)
{
 MPI_Send(Foo2D,sizeof_Foo2D,MPI_INT,1,100,MPI_COMM_WORLD);
}
else if (myrank == 1)
{
 MPI_Recv(Foo2D,sizeof_Foo2D,MPI_INT,0,100,MPI_COMM_WORLD, &status);
}

然后将排名1的收到的Foo2D分配给其在Foo3D中的位置,如下:

if (myrank == 1)
{
for (int j = 0; j < ny; j++) {
 for (int k = 0; k < nz; k++) {

   Foo3D[0][j][k] = Foo2D[j][k];
}
 } 
}

不是使用此过程并将Foo2D用作中间变量,而是可以直接将等级0的Foo3D的切片 发送到等级1的等效位置或不?实际上,我不想将整个Foo3D发送到排名1,因为它是一个非常大的数组,我很想只发送其中的一部分到排名1。

1 个答案:

答案 0 :(得分:3)

您正在将数组Foo3D定义为int[nx][ny][nz]。由于C / C ++是行主要语言,因此表示为Foo3D[0][j][k]的网格面的元素在内存中实际上是连续的

Memory Layout for i=0

因此,您可以使用以下命令将i=0的头像发送给我们:

if (myrank == 0) {
    MPI_Send(Foo3D, ny*nz, MPI_INT, 1, 100, MPI_COMM_WORLD);
}
else if (myrank == 1){
    MPI_Recv(Foo3D, ny*nz, MPI_INT, 0, 100, MPI_COMM_WORLD, &status);
}

另一方面,如果要使用缓冲区(Zero-Copy)发送不连续数据而无需,您可以创建一个表示要复制的数据的自定义MPI数据类型,并直接从源缓冲区发送,即使内存中不连续,MPI也会读取您指定的数据。可以使用MPI_Type_vector完成。

例如,如果要发送值k=0,即网格面 Foo[i][j][0]

Memory Layout for k=0

首先,创建一种数据类型,该数据类型表示要发送的网格的表面。

Diagram of MPI_Type_vector inputs

// Create a data type and save its size
MPI_Datatype cubeface;
int cubefacesize;
MPI_Type_vector(nx*ny, 1, nz, MPI_INT, &cubeface);
MPI_Type_commit(&cubeface);
MPI_Type_size(cubeface, &cubefacesize);

然后,您可以使用以下方式发送和接收:

if (myrank == 0) {
    MPI_Send(Foo3D, 1, cubeface, 1, cubefacesize, MPI_COMM_WORLD);
} else if (myrank == 1) {
    MPI_Recv(Foo3D, 1, cubeface, 0, cubefacesize, MPI_COMM_WORLD, &status);
}