0

我正在运行具有数千个 MPI 进程的模拟,并且需要将输出数据写入一小组文件。例如,即使我可能有 10,000 个进程,我只想写出 10 个文件,每个文件写入 1,000 个(在某个适当的偏移量处)。AFAIK 正确的方法是为将写入相同文件的进程组创建一个新的通信器,使用 为该通信器打开一个共享文件,MPI_File_open()然后使用MPI_File_write_at_all(). 那是对的吗?以下代码是我编写的一个玩具示例:

#include <mpi.h>
#include <math.h>
#include <stdio.h>

const int MAX_NUM_FILES = 4;

int main(){
    MPI_Init(NULL, NULL);

    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int numProcs;
    MPI_Comm_size(MPI_COMM_WORLD, &numProcs);

    int numProcsPerFile = ceil(((double) numProcs) / MAX_NUM_FILES);
    int targetFile = rank / numProcsPerFile;

    MPI_Comm fileComm;
    MPI_Comm_split(MPI_COMM_WORLD, targetFile, rank, &fileComm);

    int targetFileRank;
    MPI_Comm_rank(fileComm, &targetFileRank);

    char filename[20]; // Sufficient for testing purposes
    snprintf(filename, 20, "out_%d.dat", targetFile);
    printf(
        "Proc %d: writing to file %s with rank %d\n", rank, filename,
        targetFileRank);

    MPI_File outFile;
    MPI_File_open(
        fileComm, filename, MPI_MODE_CREATE | MPI_MODE_WRONLY,
        MPI_INFO_NULL, &outFile);

    char bufToWrite[4];
    snprintf(bufToWrite, 4, "%3d", rank);

    MPI_File_write_at_all(
        outFile, targetFileRank * 3,
        bufToWrite, 3, MPI_CHAR, MPI_STATUS_IGNORE);

    MPI_File_close(&outFile);
    MPI_Finalize();
}

我可以使用 编译mpicc file.c -lm并运行 20 个进程mpirun -np 20 a.out,并且我得到了预期的输出(四个文件,每个文件有五个条目),但我不确定这是否是技术上正确/最优化的方法。有什么我应该做的不同的事情吗?

4

3 回答 3

1

MPI_File_write_at_all 应该是最有效的方法。集体 IO 函数通常对于对共享文件的大型非连续并行写入最快,并且 _all 变体将查找和写入组合到一个调用中。

于 2017-02-24T22:04:04.537 回答
1

你的方法是正确的。为了澄清,我们需要重新审视标准和定义。MPI 的MPI_File_Open API :消息传递接口标准版本 2.2(第 391 页)

int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh)

描述:

MPI_FILE_OPEN 在 comm 通信器组中的所有进程上打开由文件名 filename 标识的文件。MPI_FILE_OPEN 是一个集体例程:所有进程必须为 amode 提供相同的值,并且所有进程必须提供引用同一文件的文件名。(信息的值可能会有所不同。) comm 必须是内部通信器;将内部通信器传递给 MPI_FILE_OPEN是错误的。

内部沟通者与内部沟通者(第 134 页):

为了本章的目的,知道有两种类型的通信器就足够了:内部通信器和内部通信器。可以将内部通信器视为与上下文链接的单个进程组的标识符。互通者识别与上下文相关联的两组不同的进程。

传递内部通信器的目的MPI_File_open()是指定一组将对文件执行操作的进程。MPI 运行时需要此信息,因此它可以在发生集体 I/O 操作时强制执行适当的同步。了解应用程序的逻辑并创建/选择正确的内部通信器是程序员的责任。

MPI_Comm_Split()在一个强大的 API 中,它允许将通信组拆分为不相交的子组,以用于不同的用例,包括 MPI I/O。

于 2017-03-04T04:48:59.893 回答
1

我认为这可能是上面的一个错字,但它是“_all”,表示集体行动。

然而,我想说的主要一点是,集体操作更快的原因是它们使 I/O 系统能够聚合来自许多进程的数据。您可以从 1000 个进程发出 1000 次写入,但使用集体形式,这可能会聚合为对文件的单个大型写入(而不是 1000 次小型写入)。这当然是最好的情况,但改进可能是巨大的——对于访问共享文件,我已经看到集体 I/O 比非集体快 1000 倍,诚然,对于比这更复杂的 IO 模式。

于 2017-03-09T18:16:46.990 回答