使用MPI I / O提取C结构的一部分

时间:2016-06-13 13:52:09

标签: c struct io mpi

我正在研究C MPI代码。它有一个结构:

typedef struct mystruct_s{
   double interesting_data;
   int boring_data;
   int trivial_data;
}mystruct;

现在,每个进程都有这些结构的数组,比如说

mystruct my_own_struct[M][N];

其中M和N是“大”,并且所有各种进程数组组成一个大的mystruct数组。

现在,我需要将interesting_data值输出到文件中的单个数组中。正如我试图用变量名称来表示,我不想输出结构的其他部分。我想使用MPI I / O来做到这一点。当然,我可以在每个进程中建立一个双数组并将interesting_data复制到其中并从那里获取它。但是,这会大大增加内存使用量,而且编码也不是非常优雅。我还在学习MPI I / O和MPI派生数据类型。有没有办法使用它们立即从结构数组中“提取”interesting_data并将其输出到具有MPI I / O的大型数组?

1 个答案:

答案 0 :(得分:4)

如果感兴趣的数据是单个double字段,那么您只需创建一个MPI_DOUBLE的调整大小版本,其范围与结构相同:

MPI_Datatype newtype;
MPI_Type_create_resized(MPI_DOUBLE, 0L, sizeof(mystruct), &newtype);
MPI_Type_commit(&newtype);

现在,当提供该数据类型时,MPI将获取一个double值,然后跳过结构的其余部分,从而降落到下一个double值。等等。

您现在可以使用例如:

存储数据
MPI_File fh;
MPI_File_open(MPI_COMM_WORLD, "interesting_data.dat",
              MPI_MODE_CREATE | MPI_MODE_WRONLY,
              MPI_INFO_NULL, &fh);
MPI_File_set_view(fh, rank * M*N * sizeof(double), // possible integer overflow!!!
                  MPI_DOUBLE, MPI_DOUBLE, "native", MPI_INFO_NULL);
MPI_File_write(fh, &my_own_struct[0][0].interesting_data, M*N, newtype,
               MPI_STATUS_IGNORE);
MPI_File_close(&fh);

MPI_File_set_view定位每个排名的文件指针,并告诉MPI不执行任何二进制转换。然后,MPI_File_write调用将合并interesting_data字段,并将它们作为单个块写入文件视图指定的位置。即使interesting_data不是结构的第一个字段,它也会起作用。

如果interesting_data包含多个结构字段,例如

typedef structure _foo
{
   int couldnt_care_less;
   double interesting_bar;
   int not_interesting;
   int interesting_baz;
   double less_interesting;
} foo;

首先应创建结构类型:

MPI_Datatype stype;
int lens[2] = { 1, 1 };
MPI_Aint disps[2] = { offsetof(foo, interesting_bar), offsetof(foo, interesting_baz) };
MPI_Datatype types[2] = { MPI_DOUBLE, MPI_INT };
MPI_Type_create_struct(2, lens, disps, types, &stype);
// MPI_Type_commit(&stype) is not necessary

现在必须调整类型的大小,与上面的简单示例完全相同:

MPI_Datatype newtype;
MPI_Aint lb, extent;
MPI_Type_get_extent(stype, &lb, &extent);
MPI_Type_create_resized(stype, lb, sizeof(foo), &newtype);
MPI_Type_commit(&newtype);

此过程使新数据类型具有与stype相同的下限,这将简化写入调用。诀窍是正确设置文件视图。它需要创建另一种结构类型,包括它们之间没有间隔的有趣字段(除非你想通过在文件中包含垃圾来浪费磁盘空间):

MPI_Datatype ftype;
int lens[2] = { 1, 1 };
MPI_Aint disps[2] = { 0, sizeof(double) };
MPI_Datatype types[2] = { MPI_DOUBLE, MPI_INT };
MPI_Type_create_struct(2, lens, disps, types, &ftype);
MPI_Type_commit(&ftype);

然后使用此数据类型设置文件视图:

// possible integer overflow!!!
MPI_Offset offset = rank * M*N * (sizeof(double) + sizeof(int));
MPI_File_set_view(fh, offset, ftype, ftype, "native", MPI_INFO_NULL);
MPI_File_write(fh, my_own_struct, M*N, newtype, MPI_STATUS_IGNORE);

这是有效的,因为ftypenewtype是一致的 - 它们由相同的基本元素(一个double和一个int)组成,并且顺序相同。< / p>