首先,我正在学习消息传递接口(MPI) https://computing.llnl.gov/tutorials/mpi/
在创建自己的MPI数据类型时,我遇到了麻烦 用它。
我的程序正在尝试获取每个象限。 说下面的4 x 4矩阵,
A = {
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0
}
所以我想将它划分为4个子矩阵,这样当master发出3个子矩阵(子矩阵1,2,3)时,每个工作者都可以接收它的相应子矩阵。
Submatrix 0 | Submatrix 1
Submatrix 2 | Submatrix 3
现在,我的程序只获取每个子矩阵的第一行,并将第二行打印为零。
以下是当前打印输出。 (您可以忽略子矩阵0)
3 4
0 0
9 10
0 0
11 12
0 0
附件是我的程序。任何指针都将非常感激。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<mpi.h>
//matrix size
#define SIZE 4
double A[SIZE][SIZE] ={
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0
};
static double B[SIZE/2][SIZE/2];
MPI_Datatype QUAD;
#define QUADRANT(Q,y,x) (Q[y * SIZE/2]+(x * SIZE/2))
void printout(double Y[SIZE/2][SIZE/2]){
int i,j;
for(i=0;i< SIZE/2;i++){
for(j=0; j< SIZE/2; j++){
printf("%.0f ",Y[i][j]);
}
printf("\n");
}
}
int main(int argc, char** argv){
int rank, size, i, j;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Status stat;
//Define a MPI datatype, Quadrant
MPI_Type_vector(SIZE/2, SIZE/2, SIZE, MPI_DOUBLE, &QUAD);
MPI_Type_commit(&QUAD);
//master process
if(rank==0){
MPI_Send(QUADRANT(A,0,1),1,QUAD,1,0, MPI_COMM_WORLD);
MPI_Send(QUADRANT(A,1,0),1,QUAD,2,0,MPI_COMM_WORLD);
MPI_Send(QUADRANT(A,1,1),1,QUAD,3,0,MPI_COMM_WORLD);
}else{
MPI_Recv(B,1,QUAD,0,0,MPI_COMM_WORLD,&stat);
printout(B);
printf("\n");
}
MPI_Finalize();
}
有类似的程序在 https://computing.llnl.gov/tutorials/mpi/samples/C/mpi_vector.c
但是试图获得列矩阵中的所有数字。
答案 0 :(得分:2)
你的大部分问题是你想要收到的不是QUAD
,而是直接的2x2子矩阵。因此,代码的发送部分很好。然而,收到的是错误的。
因此,修复代码需要做的是在发送前将象限复制到发送前的2x2矩阵中,或者分配接收方的2x4接收缓冲区来存储发送的消息,并且之后将相关部分复制到2x2矩阵中。
以下是第二个选项的代码,我选择这个选项用于说明目的,因为您似乎想要使用派生类型。 (注意:我保留了代码风格,虽然这不是我自己使用的代码风格)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<mpi.h>
//matrix size
#define SIZE 4
double A[SIZE][SIZE] ={
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0
};
static double B[SIZE/2][SIZE/2];
static double tmpB[SIZE/2][SIZE];
MPI_Datatype QUAD;
#define QUADRANT(Q,y,x) (Q[y * SIZE/2]+(x * SIZE/2))
void printout(double Y[SIZE/2][SIZE/2]){
int i,j;
for(i=0;i< SIZE/2;i++){
for(j=0; j< SIZE/2; j++){
printf("%.0f ",Y[i][j]);
}
printf("\n");
}
}
void compress(double Y[SIZE/2][SIZE/2], double tmpY[SIZE/2][SIZE]){
int i,j;
for(i=0;i< SIZE/2;i++){
for(j=0; j< SIZE/2; j++){
Y[i][j]=tmpY[i][j];
}
}
}
int main(int argc, char** argv){
int rank, size, i, j;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Status stat;
//Define a MPI datatype, Quadrant
MPI_Type_vector(SIZE/2, SIZE/2, SIZE, MPI_DOUBLE, &QUAD);
MPI_Type_commit(&QUAD);
//master process
if(rank==0){
MPI_Send(QUADRANT(A,0,1),1,QUAD,1,0,MPI_COMM_WORLD);
MPI_Send(QUADRANT(A,1,0),1,QUAD,2,0,MPI_COMM_WORLD);
MPI_Send(QUADRANT(A,1,1),1,QUAD,3,0,MPI_COMM_WORLD);
}else{
MPI_Recv(tmpB,1,QUAD,0,0,MPI_COMM_WORLD,&stat);
compress(B,tmpB);
printout(B);
printf("\n");
}
MPI_Finalize();
}
最后一句话:在现实生活中,如果你要做这种转移,我会鼓励你去发送之前将数据压缩到象限的解决方案,以避免在其中发现额外的潜在无用副本MPI库本身(尽管它们是否发生超出了MPI标准的范围)
答案 1 :(得分:2)
问题是,MPI_Recv
与相同的跨步矢量数据类型一起使用,它不符合接收缓冲区的布局。
例如,电话
MPI_Send(QUADRANT(A,0,1),1,QUAD,1,0, MPI_COMM_WORLD);
与QUAD
的定义一起正确选择A
右上象限的数据值,并通过网络发送值3.0,4.0,7.0和8.0。
但是,相同的数据类型不能用于接收缓冲区,因为B
中行的大小(因此步幅)小于A
中的行大小。因此,值7.0和8.0的存储超出了B
:
Matrix as seen by MPI_Recv Memory Layout of
with data-type QUAD Matrix B
M[0][0] <-- 3.0 --> B[0][0]
M[0][1] <-- 4.0 --> B[0][1]
M[0][2] B[1][0] <-- unchanged, e.g. 0.0
M[0][3] B[1][1] <-- unchanged, e.g. 0.0
M[1][0] <-- 7.0 --> !beyond array!
M[1][1] <-- 8.0 --> !beyond array!
M[1][2]
M[1][3]
...
编辑:符合标准,收到后必须使用相同的类型。因此,接收缓冲区必须声明如下:
double B[SIZE/2][SIZE]; // SIZE elements per row.
之后,人们可以按照Gilles的回答压缩阵列。