在 MPI 中发送结构数组
Sending array of structs in MPI
我的数据结构如下所示
struct test{
double a1;
double a2;
}
并且有一个指向结构数组开始的指针test *info = nullptr;
。
问题是如何广播这个数组而不将它转换成两个单独的向量。
- 我尝试创建 mpi_type_struct 没成功。
- 我试图打包我的结构数据,但没有成功。
到目前为止,我看到的案例仅对一个结构有效,对结构数组无效。
这是我目前尝试过的方法
int block[2] = {1,1};
MPI_Aint displacements[2];
MPI_Aint baseaddr, addr1, addr2;
MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
MPI_Datatype contigs[6];
if(my_rank==0){
for (int i = 0; i < 6; i++)
{
MPI_Get_address ( &info[i], &baseaddr);
MPI_Get_address ( &info[i].num_edges, &addr1);
MPI_Get_address ( &info[i].num_vertices, &addr2);
displs[0] = addr1 - baseaddr;
displs[1] = addr2 - baseaddr;
MPI_Type_create_struct(2, block, displacements, types, &contigs[i]);
MPI_Type_commit(&contigs[i]);
}
MPI_Bcast(info, 6, *contigs, 0, comm);
int block[2] = {1,1};
MPI_Aint displacements[2];
MPI_Aint baseaddr, addr1, addr2;
MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
MPI_Datatype contigs[6];
if(my_rank==0){
for (int i = 0; i < 6; i++)
{
MPI_Get_address ( &info[i], &baseaddr);
MPI_Get_address ( &info[i].num_edges, &addr1);
MPI_Get_address ( &info[i].num_vertices, &addr2);
displs[0] = addr1 - baseaddr;
displs[1] = addr2 - baseaddr;
MPI_Type_create_struct(2, block, displacements, types, &contigs[i]);
MPI_Type_commit(&contigs[i]);
}
您不必为数组中的每个 struct
构建。您可以改为 MPI_Type_create_struct
其中之一,然后只使用 MPI_Bcast:
完整示例:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void defineStruct(MPI_Datatype *tstype);
typedef struct S{
double a1;
double a2;
} S;
void defineStruct(MPI_Datatype *tstype) {
const int count = 2;
int blocklens[count] = {1,1};
MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
MPI_Aint disps[count] = {offsetof(S,a1), offsetof(S,a2)};
MPI_Type_create_struct(count, blocklens, disps, types, tstype);
MPI_Type_commit(tstype);
}
int main(int argc,char *argv[]){
MPI_Init(NULL,NULL);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Datatype structtype;
int total_size = 5;
S *info = malloc(sizeof(S) * total_size);
// Just adding some fake values
if(world_rank == 0){
for(int i = 0; i < total_size; i++){
info[i].a1 = i * i;
info[i].a2 = i * (i+1);
}
}
defineStruct(&structtype);
MPI_Bcast(info, total_size, structtype, 0, MPI_COMM_WORLD);
if(world_rank != 0){
for(int i = 0; i < total_size; i++){
printf("%lf %lf\n", info[i].a1, info[i].a2);
}
}
free(info);
MPI_Finalize();
return 0;
}
输出:
0.000000 0.000000
1.000000 2.000000
4.000000 6.000000
9.000000 12.000000
16.000000 20.000000
MPI_TYPE_STRUCT 不用于描述 C 结构数据类型(尽管您可以为此使用它——您可以使用 MPI_TYPE_STRUCT 做任何事情)。它用于描述由多个数据类型组成的数据类型。
'double' 非常安全,但为了处理成员填充,我认为获取每个项目的地址是正确的调用。
@dreamcrash 的解决方案创建单一数据类型并发送该类型的 'count'。另一种方法是用 MPI_TYPE_HINDEXED_BLOCK 描述内存(因为块大小总是 sizeof(double).
我的数据结构如下所示
struct test{
double a1;
double a2;
}
并且有一个指向结构数组开始的指针test *info = nullptr;
。
问题是如何广播这个数组而不将它转换成两个单独的向量。
- 我尝试创建 mpi_type_struct 没成功。
- 我试图打包我的结构数据,但没有成功。 到目前为止,我看到的案例仅对一个结构有效,对结构数组无效。
这是我目前尝试过的方法
int block[2] = {1,1};
MPI_Aint displacements[2];
MPI_Aint baseaddr, addr1, addr2;
MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
MPI_Datatype contigs[6];
if(my_rank==0){
for (int i = 0; i < 6; i++)
{
MPI_Get_address ( &info[i], &baseaddr);
MPI_Get_address ( &info[i].num_edges, &addr1);
MPI_Get_address ( &info[i].num_vertices, &addr2);
displs[0] = addr1 - baseaddr;
displs[1] = addr2 - baseaddr;
MPI_Type_create_struct(2, block, displacements, types, &contigs[i]);
MPI_Type_commit(&contigs[i]);
}
MPI_Bcast(info, 6, *contigs, 0, comm);
int block[2] = {1,1}; MPI_Aint displacements[2]; MPI_Aint baseaddr, addr1, addr2; MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE}; MPI_Datatype contigs[6]; if(my_rank==0){ for (int i = 0; i < 6; i++) { MPI_Get_address ( &info[i], &baseaddr); MPI_Get_address ( &info[i].num_edges, &addr1); MPI_Get_address ( &info[i].num_vertices, &addr2); displs[0] = addr1 - baseaddr; displs[1] = addr2 - baseaddr; MPI_Type_create_struct(2, block, displacements, types, &contigs[i]); MPI_Type_commit(&contigs[i]); }
您不必为数组中的每个 struct
构建。您可以改为 MPI_Type_create_struct
其中之一,然后只使用 MPI_Bcast:
完整示例:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void defineStruct(MPI_Datatype *tstype);
typedef struct S{
double a1;
double a2;
} S;
void defineStruct(MPI_Datatype *tstype) {
const int count = 2;
int blocklens[count] = {1,1};
MPI_Datatype types[2] = {MPI_DOUBLE, MPI_DOUBLE};
MPI_Aint disps[count] = {offsetof(S,a1), offsetof(S,a2)};
MPI_Type_create_struct(count, blocklens, disps, types, tstype);
MPI_Type_commit(tstype);
}
int main(int argc,char *argv[]){
MPI_Init(NULL,NULL);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Datatype structtype;
int total_size = 5;
S *info = malloc(sizeof(S) * total_size);
// Just adding some fake values
if(world_rank == 0){
for(int i = 0; i < total_size; i++){
info[i].a1 = i * i;
info[i].a2 = i * (i+1);
}
}
defineStruct(&structtype);
MPI_Bcast(info, total_size, structtype, 0, MPI_COMM_WORLD);
if(world_rank != 0){
for(int i = 0; i < total_size; i++){
printf("%lf %lf\n", info[i].a1, info[i].a2);
}
}
free(info);
MPI_Finalize();
return 0;
}
输出:
0.000000 0.000000
1.000000 2.000000
4.000000 6.000000
9.000000 12.000000
16.000000 20.000000
MPI_TYPE_STRUCT 不用于描述 C 结构数据类型(尽管您可以为此使用它——您可以使用 MPI_TYPE_STRUCT 做任何事情)。它用于描述由多个数据类型组成的数据类型。
'double' 非常安全,但为了处理成员填充,我认为获取每个项目的地址是正确的调用。
@dreamcrash 的解决方案创建单一数据类型并发送该类型的 'count'。另一种方法是用 MPI_TYPE_HINDEXED_BLOCK 描述内存(因为块大小总是 sizeof(double).