MPI_File_set_view 用于使用自定义 MPI_Datatype 作为文件类型的并行文件输出

MPI_File_set_view for parallel file output using custom MPI_Datatype as filetype

我很难理解 MPI_File_set_view 是如何工作的,尤其是第 4 个参数让我很困惑。

int MPI_File_set_view(MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype, const char *datarep, MPI_Info info)

假设我有 n 个线程,每个线程都有一个名为“v”的长度为 10 的字符数组,该数组的所有条目都等于线程 ID。所以

thread0: v={0,0,0,0,0,0,0,0,0,0}

thread1: v={1,1,1,1,1,1,1,1,1,1}

thread2: v={2,2,2,2,2,2,2,2,2,2}

...

现在我想按以下顺序编写一个包含这些数组值的二进制文件:

file = thread0.v[0], thread1.v[0], thread2.v[0], ..., thread0.v[1], thread1.v[1], thread2.v[1], ..., thread0.v[2], thread1.v[2], thread2.v[2], ...

据我所知,我必须为文件类型参数构造一个 MPI_Datatype,它的大小为 [sizeof(char)*n],其中有一个大小为 [sizeof( char)*threadID] 在 MPI_Char 数据之前,另一个大小为 [sizeof(char)*(n-threadID-1)] 的“洞”在数据之后。我认为这是我犯错误的部分。

我的代码如下所示:

#include<iostream>
#include<mpi.h>

using namespace std;


int main(int argc, char* argv[]){
    int myId;
    int numProcs;
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myId);
    
    int size=100;
    char v[size];
    for(int i=0;i<size;i++){
        v[i]=myId;
    }
    
    int blocklen[numProcs];
    MPI_Aint disp[numProcs];
    MPI_Datatype type[numProcs];
    for(int i=0;i<numProcs;i++){
        blocklen[i]=1;
        disp[i]=sizeof(char)*myId;
        type[i]=MPI_CHAR;
    }
    
    MPI_Datatype mytype;
    MPI_Type_create_struct(numProcs, blocklen, disp, type, &mytype);
    MPI_Type_commit(&mytype);
    
    MPI_File fh;
    MPI_File_open(MPI_COMM_WORLD, "binfile", MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);
    MPI_File_set_view(fh, 0, MPI_BYTE, mytype, "native", MPI_INFO_NULL);
    MPI_File_write(fh, v, size, MPI_BYTE, MPI_STATUS_IGNORE);
    
    MPI_File_close(&fh);
    MPI_Finalize();
    return 0;
}

当我对文件“binfile”进行 hexdump 时,我得到了这个(使用 4 个线程):

$ hd binfile

00000000 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 |................|

00000010 01 01 01 01 01 01 01 01 01 01 02 03 |............|

0000001c

我哪里出错了?

感谢 Hristo Iliev 的评论,我得以解决我的问题。 函数

int MPI_Type_create_subarray(int ndims, const int array_of_sizes[], const int array_of_subsizes[], const int array_of_starts[], int order, MPI_Datatype oldtype, MPI_Datatype *newtype)

成功了。 array_of_sizes 定义新数据类型的大小。 array_of_subsizes 定义部分的大小,它不是 "holes" 的一部分,array_of_starts 定义 "non-hole" 部分的开始位置。

对于任何感兴趣的人,这是工作代码:

#include<iostream>
#include<mpi.h>

using namespace std;


int main(int argc, char* argv[]){
    int myId;
    int numProcs;
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myId);

    int size=100;
    char v[size];
    for(int i=0;i<size;i++){
        v[i]=myId;
    }

    int array_of_sizes[1];
    array_of_sizes[0]=numProcs;
    int array_of_subsizes[1];
    array_of_subsizes[0]=1;
    int array_of_starts[1];
    array_of_starts[0]=myId;


    MPI_Datatype mytype;
    MPI_Type_create_subarray(1,array_of_sizes, array_of_subsizes, array_of_starts, MPI_ORDER_C, MPI_BYTE, &mytype);
    MPI_Type_commit(&mytype);

    MPI_File fh;
    MPI_File_open(MPI_COMM_WORLD, "binfile", MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh);
    MPI_File_set_view(fh, 0, MPI_BYTE, mytype, "native", MPI_INFO_NULL);
    MPI_File_write(fh, v, size, MPI_BYTE, MPI_STATUS_IGNORE);

    MPI_File_close(&fh);
    MPI_Finalize();
    return 0;
}