MPI 非标准类型的分布式读取
MPI Distributed reading over a non-standard type
我正在尝试读取包含一系列 char 和 double 的二进制文件。 (例如 0 0.125 1 1.4 0 2.3 1 4.5,但写在二进制文件中)。我创建了一个简单的结构输入,还有一个 MPI 数据类型,我将调用 mpi_input 对应于这个结构。
typedef struct { char type; double value } input;
我想使用 MPI_File_read_at_all
并行读取我的文件(即这里使用不同的处理器)。我想在此函数中使用数据类型 mpi_input。
问题是,我认为这个函数需要一个缓冲区,它将写入到最后。我尝试使用 input *buffer
,但这会因数据结构对齐而产生问题。您对如何执行此操作有任何想法吗?
这是一个最小的工作示例:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include <assert.h>
#include <stddef.h>
int main(int argc, char** argv)
{
typedef struct
{
double val;
char type;
} input;
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
assert(size == 4);
MPI_File in;
MPI_Offset filesize;
MPI_File_open(MPI_COMM_WORLD, argv[1], MPI_MODE_RDONLY, MPI_INFO_NULL, &in);
MPI_File_get_size(in, &filesize);
int mysize = filesize/size;
int globalstart = rank * mysize;
input *chunk = malloc(sizeof(input)*2);
int n = 128;
int m = 256;
int blocks[2] = {1,1};
MPI_Datatype types[2] = {MPI_BYTE, MPI_DOUBLE};
MPI_Aint displacements[2];
MPI_Datatype cell_type;
MPI_Aint charex, doublex;
displacements[0] = offsetof(input, type);
displacements[1] = offsetof(input, val);
MPI_Type_create_struct(2, blocks, displacements, types, &cell_type);
MPI_Type_commit(&cell_type);
MPI_File_read_at_all(in, globalstart, chunk, mysize, cell_type, MPI_STATUS_IGNORE);
if(rank == 0)
printf("0 - Got %d %f\n", chunk->val, chunk->type);
if(rank == 4)
printf("Got %d %f\n", chunk->val, chunk->type);
MPI_File_close(&in);
MPI_Finalize();
}
下面是生成简单二进制文件的代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char* filename = "test.dump";
fp = fopen(filename, "wb");
char bla = 8;
for(double i = 0; i < 8; i++)
{
fwrite(&bla, sizeof(char), 1, fp);
bla--;
fwrite(&i, sizeof(double), 1, fp);
}
fclose(fp);
}
您提供的 MPI_File_read_at_all
错误论据。在 MPI 中,与数据相关的参数 send/received/read/written 几乎总是作为以下形式的三元组给出:buffer, #elements, datatype
.
在您的例子中,#elements
等于 mysize
,它以字节为单位,而不是数据类型 cell_type
的元素数量。结果,该函数读取的元素超过缓冲区所能容纳的元素,从而破坏了堆。
您应该做的是将 mysize
除以数据类型的大小(那是 而不是 sizeof(input)
!):
int cell_type_size;
MPI_Type_size(cell_type, &cell_type_size);
...
MPI_File_read_at_all(in, globalstart,
chunk, mysize / cell_type_size, cell_type, MPI_STATUS_IGNORE);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// data specification triplet
此外,您的第二个 printf
语句将永远不会执行,因为在 4 个 MPI 进程的情况下 rank
从 0
到 3
不等。
我正在尝试读取包含一系列 char 和 double 的二进制文件。 (例如 0 0.125 1 1.4 0 2.3 1 4.5,但写在二进制文件中)。我创建了一个简单的结构输入,还有一个 MPI 数据类型,我将调用 mpi_input 对应于这个结构。
typedef struct { char type; double value } input;
我想使用 MPI_File_read_at_all
并行读取我的文件(即这里使用不同的处理器)。我想在此函数中使用数据类型 mpi_input。
问题是,我认为这个函数需要一个缓冲区,它将写入到最后。我尝试使用 input *buffer
,但这会因数据结构对齐而产生问题。您对如何执行此操作有任何想法吗?
这是一个最小的工作示例:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include <assert.h>
#include <stddef.h>
int main(int argc, char** argv)
{
typedef struct
{
double val;
char type;
} input;
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
assert(size == 4);
MPI_File in;
MPI_Offset filesize;
MPI_File_open(MPI_COMM_WORLD, argv[1], MPI_MODE_RDONLY, MPI_INFO_NULL, &in);
MPI_File_get_size(in, &filesize);
int mysize = filesize/size;
int globalstart = rank * mysize;
input *chunk = malloc(sizeof(input)*2);
int n = 128;
int m = 256;
int blocks[2] = {1,1};
MPI_Datatype types[2] = {MPI_BYTE, MPI_DOUBLE};
MPI_Aint displacements[2];
MPI_Datatype cell_type;
MPI_Aint charex, doublex;
displacements[0] = offsetof(input, type);
displacements[1] = offsetof(input, val);
MPI_Type_create_struct(2, blocks, displacements, types, &cell_type);
MPI_Type_commit(&cell_type);
MPI_File_read_at_all(in, globalstart, chunk, mysize, cell_type, MPI_STATUS_IGNORE);
if(rank == 0)
printf("0 - Got %d %f\n", chunk->val, chunk->type);
if(rank == 4)
printf("Got %d %f\n", chunk->val, chunk->type);
MPI_File_close(&in);
MPI_Finalize();
}
下面是生成简单二进制文件的代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char* filename = "test.dump";
fp = fopen(filename, "wb");
char bla = 8;
for(double i = 0; i < 8; i++)
{
fwrite(&bla, sizeof(char), 1, fp);
bla--;
fwrite(&i, sizeof(double), 1, fp);
}
fclose(fp);
}
您提供的 MPI_File_read_at_all
错误论据。在 MPI 中,与数据相关的参数 send/received/read/written 几乎总是作为以下形式的三元组给出:buffer, #elements, datatype
.
在您的例子中,#elements
等于 mysize
,它以字节为单位,而不是数据类型 cell_type
的元素数量。结果,该函数读取的元素超过缓冲区所能容纳的元素,从而破坏了堆。
您应该做的是将 mysize
除以数据类型的大小(那是 而不是 sizeof(input)
!):
int cell_type_size;
MPI_Type_size(cell_type, &cell_type_size);
...
MPI_File_read_at_all(in, globalstart,
chunk, mysize / cell_type_size, cell_type, MPI_STATUS_IGNORE);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// data specification triplet
此外,您的第二个 printf
语句将永远不会执行,因为在 4 个 MPI 进程的情况下 rank
从 0
到 3
不等。