MPI 派生数据类型 MPI_Type_create_struct(),MPI_Type_contiguous(),MPI_Type_vector(),MPI_Type_create_hvector(),MPI_Type_indexed()

时间:2023-03-09 19:24:12
MPI 派生数据类型 MPI_Type_create_struct(),MPI_Type_contiguous(),MPI_Type_vector(),MPI_Type_create_hvector(),MPI_Type_indexed()

▶ 使用 MPI 派生数据类型,减少数据在传输过程中的耗时

● MPI_Type_create_struct() 范例代码

 {
const int globalSize = ;
int globalDataInt[globalSize], globalDataDouble[globalSize];
int i, comSize, comRank, randomInt, sumInt;
double sumDouble; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); // 创建派生数据类型,包含 1 个整形数组,1 个浮点数组和 1 个整形的结构。创建过程只与数据类型有关而与数据的值无关,每个进程都进行了创建
int blockLength[] = { globalSize,globalSize, }; // 各成员的长度
MPI_Aint globalDataInt_p, globalDataDouble_p, randomInt_p; // 获取各成员的地址,以计算偏移量
MPI_Get_address((void *)globalDataInt, &globalDataInt_p);
MPI_Get_address((void *)globalDataDouble, &globalDataDouble_p);
MPI_Get_address((void *)&randomInt, &randomInt_p);
MPI_Aint displacement[] = { , globalDataDouble_p - globalDataInt_p,randomInt_p - globalDataInt_p };// 计算各成员地址关于第一个成员的偏移量
int type[] = { MPI_INT,MPI_DOUBLE,MPI_INT }; // 各成员的数据类型
MPI_Datatype newType; // 调用内建函数创建新类型
MPI_Type_create_struct(, blockLength, displacement, type, &newType);
MPI_Type_commit(&newType); // 提交新类型,以便像 MPI_Datatype 那样使用 if (comRank == )
{
for (i = ; i < globalSize; globalDataInt[i] = i, globalDataDouble[i] = (double)i, i++);
randomInt = ;
} MPI_Bcast(globalDataInt, , newType, , MPI_COMM_WORLD);// 发送数据到各进程,使用的数据指针是派生数据类型中首个成员的数据的指针 for (i = sumInt = , sumDouble = 0.0; i < globalSize; i++)
{
sumInt += globalDataInt[i];
sumDouble += globalDataDouble[i];
}
printf("Size = %d, rank = %d, resultInt = %d, resultDouble = %f, randomInt = %d\n", comSize, comRank, sumInt, sumDouble, randomInt); MPI_Type_free(&newType);
MPI_Finalize();
return ;// 输出结果:八个进程乱序输出诸如 Size = 8, rank = 4, resultInt = 28, resultDouble = 28.000000, randomInt = 120994 的结果
}

● 用到的函数

 // 创建派生数据类型
MPI_METHOD MPI_Type_create_struct(
_In_range_(>= , ) int count, // 成员个数
_mpi_reads_(count) const int array_of_blocklengths[], // 各成员的长度,1 为标量,大于 1 为矢量
_mpi_reads_(count) const MPI_Aint array_of_displacements[], // 各成员地址关于第一个成员的偏移量,以便 MPI 整合数据
_mpi_reads_(count) const MPI_Datatype array_of_types[], // 成员数据类型
_Out_ MPI_Datatype* newtype // 传入一个 MPI_Datatype* 类型的指针,用于输出所创建的类型
); // 提交创建的数据类型以便使用
MPI_METHOD
MPI_Type_commit(_In_ MPI_Datatype* datatype);// 传入使用函数 MPI_Type_create_struct() 创建的类型,之后就能像使用 MPI_Datatype 那样使用创建的数据类型了 MPI_METHOD MPI_Type_free(_Deref_out_range_(== , MPI_DATATYPE_NULL) _Inout_ MPI_Datatype* datatype);
// 使用自定义的类型需要额外的空间开销,是使用完毕后要释放空间,需要传入创建个点类型

▶ 其他几个派生数据类型的函数原型

 MPI_METHOD MPI_Type_contiguous(
_In_range_(>= , ) int count, // 数据个数
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_vector(
_In_range_(>= , ) int count, // 数据个数
_In_range_(>= , ) int blocklength, // 每个数据的宽度(即每个数据本身可以是一个矢量)
_In_ int stride, // 相邻数据之间的跨步(&a[n+1] - &a[n],a[n] 内部不是什么不重要)
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_create_hvector(
_In_range_(>= , ) int count, // 元素个数
_In_range_(>= , ) int blocklength, // 元素宽度(个数为单位)
_In_ MPI_Aint stride, // 相邻元素跨度(字节为单位)
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
); MPI_METHOD MPI_Type_indexed(
_In_range_(>=, ) int count, // 元素个数
_mpi_reads_(count) const int array_of_blocklengths[], // 元素宽度
_mpi_reads_(count) const int array_of_displacements[], // 每个元素关于首元的偏移量
_In_ MPI_Datatype oldtype, // 原数据类型
_Out_ MPI_Datatype* newtype // 新数据名
);

● 函数 MPI_Type_contiguous() 和 MPI_Type_vector() 范例

 // 将整形数组中连续 7 个元素封装为一个 newType 进行消息传递
{
MPI_Datatype newType;
MPI_Type_contiguous(, MPI_INT, &newType);
MPI_Type_commit(&newType);
} // 将二维数组 a[11][13] 中某两列前 7 个元素封装为一个 newType 进行消息传递
{
MPI_Datatype newType;
MPI_Type_vector(, , , MPI_INT, &newType);// 注意每个元素宽度为 2,跨度为 13(即一行的元素个数)
MPI_Type_commit(&newType);
}

● 函数 MPI_Type_create_hvector() 的范例

 {
const int dataSize = ;
MPI_Datatype int3, type;
int comRank, comSize, i, data[dataSize]; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); MPI_Type_contiguous(, MPI_INT, &int3);// 连续三个整形组一个 int3
MPI_Type_commit(&int3);
MPI_Type_create_hvector(, , * sizeof(int), int3, &type);// 一个 type 包含 3 个元素,每个元素由连续两个 int3 组成,3 个元素之间跨度为 7 个整形
MPI_Type_commit(&type);
if (comRank == )// 0 号进程发送一个 type 给 1 号进程
{
for (i = ; i < dataSize; data[i] = i, i++);
MPI_Send(data, , type, ,, MPI_COMM_WORLD);
}
if (comRank == )
{
for (i = ; i < dataSize; data[i++] = -);
MPI_Recv(data, , type, , , MPI_COMM_WORLD,MPI_STATUS_IGNORE);
for (i = ; i < dataSize; i++)
printf("%3d, ", data[i]);
fflush(stdout);
} MPI_Finalize();
return ;
}

● 输出结果,连续 6 个元素断一下

D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n  -l MPIProjectTemp.exe
[] , , , , , , -, , , , , , , -, , , , , , , -,

● 函数 MPI_Type_indexed() 范例

 {
const int dataSize = ;
MPI_Datatype int3, type;
int comRank, comSize, i, data[dataSize], blocklen[] = { , , }, displacement[] = { , , }; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &comSize);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank); MPI_Type_contiguous(, MPI_INT, &int3);
MPI_Type_commit(&int3);
MPI_Type_indexed(, blocklen, displacement, int3, &type);// 一个 type 包含 3 个元素,每个元素分别由 blocklen[i] 个 int3 组成,各元素之间跨度为 displacement[i] 个 int3 形
MPI_Type_commit(&type); if (comRank == )
{
for (i = ; i < dataSize; data[i] = i, i++);
MPI_Send(data, , type, , , MPI_COMM_WORLD);
}
if (comRank == )
{
for (i = ; i < dataSize; data[i++] = -);
MPI_Recv(data, , type, , , MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
for (i = ; i<dataSize; i++)
printf("%3d, ", data[i]);
fflush(stdout);
} MPI_Finalize();
return ;
}

● 输出结果,分别为 6 个、9 个、3 个元素,偏移位置分别为第 0,3,8 个 int3 的起点位置

D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n  -l MPIProjectTemp.exe
[] , , , , , , -, -, -, , , , , , , , , , -, -, -, -, -, -, , , ,

▶ 其他派生数据类型,等待补全

 MPI_METHOD MPI_Type_create_hindexed(
_In_range_(>= , ) int count,
_mpi_reads_(count) const int array_of_blocklengths[],
_mpi_reads_(count) const MPI_Aint array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_hindexed_block(
_In_range_(>= , ) int count,
_In_range_(>= , ) int blocklength,
_mpi_reads_(count) const MPI_Aint array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_indexed_block(
_In_range_(>= , ) int count,
_In_range_(>= , ) int blocklength,
_mpi_reads_(count) const int array_of_displacements[],
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); MPI_METHOD MPI_Type_create_subarray(
_In_range_(>= , ) int ndims,
_mpi_reads_(ndims) const int array_of_sizes[],
_mpi_reads_(ndims) const int array_of_subsizes[],
_mpi_reads_(ndims) const int array_of_starts[],
_In_range_(MPI_ORDER_C, MPI_ORDER_FORTRAN) int order,
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
); _Pre_satisfies_(order == MPI_DISTRIBUTE_DFLT_DARG || (order >= MPI_DISTRIBUTE_BLOCK && order <= MPI_DISTRIBUTE_NONE))
MPI_METHOD MPI_Type_create_darray(
_In_range_(>= , ) int size,
_In_range_(>= , ) int rank,
_In_range_(>= , ) int ndims,
_mpi_reads_(ndims) const int array_of_gsizes[],
_mpi_reads_(ndims) const int array_of_distribs[],
_mpi_reads_(ndims) const int array_of_dargs[],
_mpi_reads_(ndims) const int array_of_psizes[],
_In_ int order,
_In_ MPI_Datatype oldtype,
_Out_ MPI_Datatype* newtype
);