在MPI中,除了有与C语言类似的MPI_INT, MPI_DOUBLE等内建类型外,还提供了用户自定义的衍生类型(Derived Datatype)。
MPI_Type_vector
最简单也是最常用的衍生数据类型就是这个向量类型,声明方法为:
MPI_Type_vector(count, blocklen, stride, oldtype, newtype);
参数
count表示数据块的重复次数,
blocklen表示单一数据块的数据长度,
stride表示数据块重复一次的总长度,如下图所示
stride=5 | |||||||||||||||||
X | X | X | X | X | X | X | X | X | X | X | X | ||||||
blocklen=3 | |||||||||||||||||
count=4 |
oldtype表示的是存放原始数据的数组中元素的类型,一般为
MPI_INT或
MPI_DOUBLE等内建类型,当然也可也是衍生类型。而
newtype则就是一个
MPI_Datatype类型的变量,用来表示新生成的数据类型。为了使数据类型生成,还需要在声明后进行执行:
MPI_Type_commit(newtype);
下面的例子中,0号处理器使用一维数组存放一个矩阵, 将它最右边的一列传递给1号处理器并存放在一个空矩阵的最左一列。然后0号处理器再将右下角的四分之一矩阵传递给2号处理器,并存放在左下角。
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int rank, size,nx,ny,row,col,count,blocklen,stride;
double *A;
MPI_Status status;
MPI_Datatype newtype;
MPI_Datatype quarterType;
MPI_Init(&argc, &argv); /* Initialize MPI */
MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get the number of processors */
MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Get my number */
nx=8; ny=16;
A=(double *)calloc(nx*ny,sizeof(double));
if (rank==0){
printf("Matrix A on proc 0\n");
for (row=0; row<nx;row++){
for (col=0; col<ny;col++){
A[row*ny+col]=(double)col+100*row+1000;
printf("%d ", (int)A[row*ny+col]);
}
printf("\n");
}
printf("\n");
}
/* left colummn to right column*/
count=nx; blocklen=1; stride=ny;
MPI_Type_vector(count,blocklen,stride,MPI_DOUBLE,&newtype);
MPI_Type_commit(&newtype);
/* right bottom quarter to left bottom quarter*/
blocklen = ny/2;
stride = ny;
count = nx /2;
MPI_Type_vector(count,blocklen,stride,MPI_DOUBLE,&quarterType);
MPI_Type_commit(&quarterType);
/* Send last column, notice the message length = 1 ! */
if (rank == 0) {
MPI_Send(&A[ny-1], 1, newtype, 1, 111, MPI_COMM_WORLD);
MPI_Send(&A[ny * nx / 2 + ny / 2], 1, quarterType, 2, 222, MPI_COMM_WORLD);
}
else if (rank==1) {
MPI_Recv(&A[0], 1, newtype, 0, 111, MPI_COMM_WORLD, &status);
printf("Matrix A on proc 1\n");
for (row=0; row<nx; row++)
{
for (col=0; col<ny; col++)
printf("%4d ", (int)A[row*ny+col]);
printf("\n");
}
}
else if (rank == 2) {
MPI_Recv(&A[ny * nx / 2], 1, quarterType, 0, 222, MPI_COMM_WORLD, &status);
printf("Matrix A on proc 2\n");
for (row=0; row<nx; row++)
{
for (col=0; col<ny; col++)
printf("%4d ", (int)A[row*ny+col]);
printf("\n");
}
}
free(A);
MPI_Type_free(&newtype);
MPI_Finalize();
return 0;
}
注意,在使用衍生类型的时候,由于类型已经包含了所有需要的元素,因此,发送或者接收时
count的值应该为1或者是相应的值,而不是原来数组的长度。
MPI_Type_indexed
这个衍生类型比前一种向量类型更加自由的一种数组类型,它的调用方法为:
MPI_Type_indexed(count, lenarr, indexarr, oldtype, newtype);参数的具体意义如下图所示,其中 indexarr表示的是每个元素的起始位置在原始数据中的index, lenarr则是指每个数据块的长度。
indexarr[0]=2 | indexarr[1]=8 | indexarr[2]=15 | |||||||||||||||
↓ | ↓ | ↓ | |||||||||||||||
X | X | X | X | X | X | X | X | X | X | X | |||||||
lenarr[0]=3 | lenarr[1]=5 | lenarr[2]=3 |
MPI_Type_struct
这种数据类型比前面两种更加自由,它不仅可以包含不同长度的数据块作为数组元素,还可以包含不同数据类型的数据块,调用方法为:
MPI_Type_struct(count, lenarr, indexarr, typearr, newtype);
其中,
typearr就表示了对应元素的数据类型。