【MPI】当MPI_Scatterv遇上MPI_Type_vector

在写按块矩阵乘时,会遇到将矩阵按块划分,然后分发给各个节点。此时方便的做法是定义MPI_Type_vector数据类型,表示矩阵的一小块,然后通过MPI_Scatter将矩阵散发到各个节点。但通过简单的MPI_Scatter进行操作时,一直出现错误,最终发现是我把MPI_Scatter想的太简单了。

原做法:

//row_block_data为每块的行数(分块矩阵行列数相同)
//N代表原始大矩阵的行数(原始大矩阵行列相同)
//dataA为原始大矩阵首地址,dA为每个节点上小矩阵的首地址
MPI_Type_vector(row_block_data,row_block_data,N,MPI_INT,&matrix_block);
MPI_Type_commit(&matrix_block);
MPI_Scatter(dataA,1,matrix_block,dA,row_block_data*row_block_data,MPI_INT,0,MPI_COMM_WORLD);

这样做会出现数据溢出等一系列错误。经查证,正确做法应为如下:

//首先通过MPI_Type_create_resized函数重置每次MPI_Scatter(v)移动的间隔,如果不重置,则每次MPI_Scatter移动的间隔为row_block_data*N;重置后MPI_Scatter每次移动间隔为row_block_data.
     MPI_Type_vector(row_block_data,row_block_data,N,MPI_INT,&tmp_block);
     MPI_Type_create_resized(tmp_block,0,row_block_data*sizeof(int),&matrix_block);
     MPI_Type_commit(&matrix_block);

//然后定义MPI_Scatterv每次移动的间隔,如下定义会使每次移动每个小block大小。
     int *scounts = (int *)malloc(size*sizeof(int));
     int *displs = (int *)malloc(size*sizeof(int));
     int disp = 0;
     for(int i=0;i<row_block_proc;i++){
	     for(int j=0;j<row_block_proc;j++){
	     	displs[i*row_block_proc+j] = j + i * row_block_data*row_block_proc;
	     }
     }
//最后通过MPI_Scatterv将大矩阵按每个小的block分发到各个节点。
        MPI_Scatterv(dataA,scounts,displs,matrix_block,dA,row_block_data*row_block_data,MPI_INT,0,MPI_COMM_WORLD);

如下代码实现的功能为,将A,B两个矩阵按cannon法进行分发初始化。(如下图,将A(左),B(中)两个矩阵按右边的方式分发到各个节点上)

     MPI_Type_vector(row_block_data,row_block_data,N,MPI_INT,&tmp_block);
     MPI_Type_create_resized(tmp_block,0,row_block_data*sizeof(int),&matrix_block);
     MPI_Type_commit(&matrix_block);

     int *scounts = (int *)malloc(size*sizeof(int));
     int *displs = (int *)malloc(size*sizeof(int));
     int disp = 0;
     for(int i=0;i<row_block_proc;i++){
	     disp = i*row_block_data*row_block_proc;
	     for(int j=0;j<row_block_proc;j++){
	     	displs[i*row_block_proc+j] = disp + (j + i + X_size)%X_size;
	     	scounts[i*row_block_proc+j] = 1;
	     }
     }
     MPI_Scatterv(dataA,scounts,displs,matrix_block,dA,row_block_data*row_block_data,MPI_INT,0,MPI_COMM_WORLD);
     disp = 0;
     for(int i=0;i<row_block_proc;i++){
	     for(int j=0;j<row_block_proc;j++){
	     	disp = j*row_block_proc;
	     	displs[i*row_block_proc+j] = j + ((j + i + Y_size)%Y_size) * row_block_data*row_block_proc;
	     }
     }
     MPI_Scatterv(dataB,scounts,displs,matrix_block,dB,row_block_data*row_block_data,MPI_INT,0,MPI_COMM_WORLD);

**************注意***********

在进行数据申请时,二维矩阵dataA,不能通过**dataA通过两次malloc进行申请,这样会造成数据不连续,后续在进行MPI_Scatterv时会出现意想不到的错误。

参考链接:

https://stackoverflow.com/questions/9269399/sending-blocks-of-2d-array-in-c-using-mpi/9271753#9271753

发布了46 篇原创文章 · 获赞 14 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/xll_bit/article/details/103112821
mpi