我在MPI_Send
和MPI_Recv
通信中遇到问题,我从进程发送列并由另一个进程收到。
为了进行调试,我在下面给出了一个基本示例,其中我使用x0
和x_domain = 4
初始化10x10矩阵(y_domain = 4
数组)。对于测试,我只需使用x0[i][j] = i+j
初始化2D数组值。
您是否可以尝试编译并执行以下测试代码,只需从rank=2
发送一列并由rank=0
收到(您需要使用nproc=4
执行):< / p>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"
int main(int argc, char *argv[])
{
/* size of the discretization */
double** x;
double** x0;
int bonk1, bonk2;
int i,j,k,l;
int nproc;
int ndims;
int S=0, E=1, N=2, W=3;
int NeighBor[4];
int xcell, ycell, size_tot_x, size_tot_y;
int *xs,*ys,*xe,*ye;
int size_x = 4;
int size_y = 4;
int me;
int x_domains=2;
int y_domains=2;
int flag = 1;
MPI_Comm comm, comm2d;
int dims[2];
int periods[2];
int reorganisation = 0;
int row;
MPI_Datatype column_type;
MPI_Status status;
size_tot_x=size_x+2*x_domains+2;
size_tot_y=size_y+2*y_domains+2;
xcell=(size_x/x_domains);
ycell=(size_y/y_domains);
MPI_Init(&argc, &argv);
comm = MPI_COMM_WORLD;
MPI_Comm_size(comm,&nproc);
MPI_Comm_rank(comm,&me);
x = malloc(size_tot_y*sizeof(double*));
x0 = malloc(size_tot_y*sizeof(double*));
for(j=0;j<=size_tot_y-1;j++) {
x[j] = malloc(size_tot_x*sizeof(double));
x0[j] = malloc(size_tot_x*sizeof(double));
}
xs = malloc(nproc*sizeof(int));
xe = malloc(nproc*sizeof(int));
ys = malloc(nproc*sizeof(int));
ye = malloc(nproc*sizeof(int));
/* Create 2D cartesian grid */
periods[0] = 0;
periods[1] = 0;
ndims = 2;
dims[0]=x_domains;
dims[1]=y_domains;
MPI_Cart_create(comm, ndims, dims, periods, reorganisation, &comm2d);
/* Identify neighbors */
NeighBor[0] = MPI_PROC_NULL;
NeighBor[1] = MPI_PROC_NULL;
NeighBor[2] = MPI_PROC_NULL;
NeighBor[3] = MPI_PROC_NULL;
/* Left/West and right/Est neigbors */
MPI_Cart_shift(comm2d,0,1,&NeighBor[W],&NeighBor[E]);
/* Bottom/South and Upper/North neigbors */
MPI_Cart_shift(comm2d,1,1,&NeighBor[S],&NeighBor[N]);
/* coordinates of current cell with me rank */
xcell=(size_x/x_domains);
ycell=(size_y/y_domains);
ys[me]=(y_domains-me%(y_domains)-1)*(ycell+2)+2;
ye[me]=ys[me]+ycell-1;
for(i=0;i<=y_domains-1;i++)
{xs[i]=2;}
for(i=0;i<=y_domains-1;i++)
{xe[i]=xs[i]+xcell-1;}
for(i=1;i<=(x_domains-1);i++)
{ for(j=0;j<=(y_domains-1);j++)
{
xs[i*y_domains+j]=xs[(i-1)*y_domains+j]+xcell+2;
xe[i*y_domains+j]=xs[i*y_domains+j]+xcell-1;
}
}
for(i=0;i<=size_tot_y-1;i++)
{ for(j=0;j<=size_tot_x-1;j++)
{ x0[i][j]= i+j;
}
}
/* Create column data type to communicate with South and North neighbors */
MPI_Type_vector( ycell, 1, size_tot_x, MPI_DOUBLE, &column_type);
MPI_Type_commit(&column_type);
if(me==2) {
printf("Before Send - Process 2 subarray\n");
for(i=ys[me]-1;i<=ye[me]+1;i++)
{ for(j=xs[me]-1;j<=xe[me]+1;j++)
{ printf("%f ",x0[i][j]);
}
printf("\n");
}
printf("\n");
MPI_Send(&(x0[ys[2]][xs[2]]), 1, column_type, 0, flag, comm2d );
}
if(me==0) {
MPI_Recv(&(x0[ys[0]][xe[0]]), 1, column_type, 2, flag, comm2d , &status);
printf("After Receive - Process 0 subarray\n");
for(i=ys[me]-1;i<=ye[me]+1;i++)
{ for(j=xs[me]-1;j<=xe[me]+1;j++)
{ printf("%f ",x0[i][j]);
}
printf("\n");
}
printf("\n");
MPI_Get_count(&status,column_type,&bonk1);
MPI_Get_elements(&status,MPI_DOUBLE,&bonk2);
printf("got %d elements of type column_type\n",bonk1);
printf("which contained %d elements of type MPI_DOUBLE\n",bonk2);
printf("\n");
}
for(i=0;i<=size_tot_y-1;i++)
{
free(x[i]);
free(x0[i]);
}
free(x);
free(x0);
free(xs);
free(xe);
free(ys);
free(ye);
MPI_Finalize();
return 0;
}
xs[me]
和xe[me]
分别对应x_start[me]
的{{1}}和x_end[me]
。 rank = me
和ys[me]
也是如此。
正如我在先前帖子中所说,只有第ye[me]
级进程收到的第一列值。这是该程序的输出:
0
我得到Before Send - Process 2 subarray
10.000000 11.000000 12.000000 13.000000
11.000000 **12.000000** 13.000000 14.000000
12.000000 **13.000000** 14.000000 15.000000
13.000000 14.000000 15.000000 16.000000
After Receive - Process 0 subarray
6.000000 7.000000 8.000000 9.000000
7.000000 8.000000 **12.000000** 10.000000
8.000000 9.000000 **10.000000** 11.000000
9.000000 10.000000 11.000000 12.000000
got 1 elements of type column_type
which contained 2 elements of type MPI_DOUBLE
第一个元素,但对于第二个元素,我有12.00000
而不是10.00000
。
我通过以下方式定义13.00000
column_type
MPI_Type_vector( ycell, 1, size_tot_x, MPI_DOUBLE, &column_type);
MPI_Type_commit(&column_type);
等于全局数组size_tot_x
的总列数。
任何帮助都会非常感激。
答案 0 :(得分:0)
这不是MPI问题,而是如何在内存中分配数组的问题。
在分配2维和更高维数组时,基本上有两种“思想流派”。 MPI也遵循的旧学校使用平面阵列 - 行在内存中一个接一个地定位。这就是编译器如何在存储器中布置明确形状的数组,例如double x[4][4]
将具有以下布局:
x[0][0] x[0][1] x[0][2] x[0][3] x[1][0] x[1][1] ... x[3][2] x[3][3]
使用这样的布局,x[i][k]
和x[i+1][k]
之间的距离(元素数量)正好等于行中元素的数量,在这种情况下为4
。当您在MPI中构造一个块长度为1
且步幅为4
的衍生向量数据类型时,当用于发送或接收数据时,它将使用同一列中的元素。
此模型的一个缺点是,当一个人动态分配内存时,必须使用类似x[4*i+k]
而不是简单x[i][k]
的内容显式计算数组内的偏移量。
第二种思想使用指向每一行的指针数组,然后分别分配每一行。这个机制很好,因为它允许构造“锯齿状”数组,并允许使用x[i][k]
语法,但不保证在内存中相邻的行是相邻的,即x[i]
和x[i+1]
可能指向超过4
个元素的位置。
您应该做的是切换逻辑以使用平面数组,或者您可以使用混合模型 - 使用malloc()
分配的平面数组,然后创建行索引:
double** x;
double** x0;
x = malloc(size_tot_y*sizeof(double*));
x0 = malloc(size_tot_y*sizeof(double*));
for(j=0;j<=size_tot_y-1;j++) {
x[j] = malloc(size_tot_x*sizeof(double));
x0[j] = malloc(size_tot_x*sizeof(double));
}
...
for(i=0;i<=size_tot_y-1;i++)
{
free(x[i]);
free(x0[i]);
}
free(x);
free(x0);
应该成为
double* x_vals;
double** x;
double* x0_vals;
double** x0;
x_vals = malloc(size_tot_x*size_tot_y*sizeof(double));
x0_vals = malloc(size_tot_x*size_tot_y*sizeof(double));
x = malloc(size_tot_y*sizeof(double*));
x0 = malloc(size_tot_y*sizeof(double*));
for(j=0;j<=size_tot_y-1;j++) {
x[j] = &x_vals[j*size_tot_x];
x0[j] = &x0_vals[j*size_tot_x];
}
...
free(x);
free(x_vals);
free(x0);
free(x0_vals);
我希望你的代码和我建议的内容之间的区别是明确的。