MPI I/O,单输出和 multiple-process 输出的混合
MPI I/O, mix of single- and multiple-process output
我需要一个 MPI C 代码来通过 MPI 将数据写入二进制文件 I/O。我需要进程 0 写一个短 header,然后我需要进程的整个范围写自己的 header 所指示的数组块。然后我需要进程 0 来写另一个 header,然后所有进程都写下一个数组的片段,等等。我想出了下面的测试代码,它实际上做了我想要的。没有人会比我更惊讶。
我的问题是,我是 MPI 的新人 I/O。我也是"getting it"吗?我这样做是 "right way" 还是有一些更有效或更紧凑的方法来做到这一点?
代码是:(顺便说一句,如果你想测试这个,只用 4 个 proc 试试。)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mpi.h"
#define ROWS 9
#define COLS 10
int main(int argc, char *argv[]) {
int size_mpi, rank_mpi, row_mpi, col_mpi;
int i,j,p,ttlcols;
int sizes[]= {2*ROWS,2*COLS};
int subsizes[]= {ROWS,COLS};
int starts[] = {0,0};
int vals[ROWS][COLS];
char hdr[] = "This is just a header.\n";
MPI_Status stat_mpi;
MPI_Datatype subarray;
MPI_File fh;
MPI_Offset offset, end_of_hdr;
MPI_Info info_mpi;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&size_mpi);
MPI_Comm_rank(MPI_COMM_WORLD,&rank_mpi);
ttlcols = 2*COLS;
/* Where are we in the array of processes? */
col_mpi = rank_mpi%2;
row_mpi = rank_mpi/2;
/* Populate the array */
for (j=0; j<ROWS; j++){
for (i=0; i<COLS; i++){
vals[j][i] = ttlcols*(ROWS*row_mpi + j) +
COLS*col_mpi + i;
}
}
/* MPI derived datatype for setting a file view */
starts[0] = row_mpi*ROWS;
starts[1] = col_mpi*COLS;
MPI_Type_create_subarray(2, sizes, subsizes, starts,
MPI_ORDER_C, MPI_INT,
&subarray);
MPI_Type_commit(&subarray);
/* open the file */
printf("opening file\n");
MPI_File_open(MPI_COMM_WORLD, "arrdata.dat",
MPI_MODE_WRONLY | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh);
printf("opened file\n");
/* set the initial file view */
MPI_File_set_view(fh, 0, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
/* proc 0 writes first header */
if (rank_mpi == 0) {
MPI_File_write(fh, (void*)hdr, strlen(hdr), MPI_CHAR, &stat_mpi);
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
}
/* everybody has to know where proc 0 stopped writing */
MPI_Bcast((void*)&end_of_hdr, 1, MPI_INT, 0, MPI_COMM_WORLD);
/* re-set file view for writing first array */
MPI_File_set_view(fh, end_of_hdr, MPI_INT,
subarray, "native",
MPI_INFO_NULL);
/* and write the array */
MPI_File_write(fh, (void*)vals, ROWS*COLS, MPI_INT,
&stat_mpi);
/* now go through the whole thing again to test */
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
MPI_File_set_view(fh, end_of_hdr, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
if (rank_mpi == 0) {
MPI_File_write(fh, (void*)hdr, strlen(hdr), MPI_CHAR, &stat_mpi);
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
}
MPI_Bcast((void*)&end_of_hdr, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_File_set_view(fh, end_of_hdr, MPI_INT,
subarray, "native",
MPI_INFO_NULL);
MPI_File_write(fh, (void*)vals, ROWS*COLS, MPI_INT,
&stat_mpi);
MPI_File_close(&fh);
MPI_Finalize();
return 0;
}
您的方法很好,如果您现在需要一些东西来将位放入文件中,请继续并完成任务。
这里有一些提高效率的建议:
您可以查询状态对象以了解写入了多少字节,而不是获取位置并转换为字节。
如果您有足够的内存在写入之前保存所有数据,则可以使用 MPI 数据类型来描述您的 I/O(无可否认,创建这种数据类型可能会很痛苦) ).然后所有进程将发出一个单一的集体调用。
你应该使用集体I/O而不是独立I/O。 "quality library" 应该能够为您提供相同甚至更好的性能(如果不能,您可以通过 MPI 实现提出问题)。
如果进程有不同数量的数据要写入,MPI_EXSCAN 是收集谁有什么数据的好方法。然后你可以调用 MPI_FILE_WRITE_AT_ALL 到文件中的正确偏移量。
我需要一个 MPI C 代码来通过 MPI 将数据写入二进制文件 I/O。我需要进程 0 写一个短 header,然后我需要进程的整个范围写自己的 header 所指示的数组块。然后我需要进程 0 来写另一个 header,然后所有进程都写下一个数组的片段,等等。我想出了下面的测试代码,它实际上做了我想要的。没有人会比我更惊讶。
我的问题是,我是 MPI 的新人 I/O。我也是"getting it"吗?我这样做是 "right way" 还是有一些更有效或更紧凑的方法来做到这一点?
代码是:(顺便说一句,如果你想测试这个,只用 4 个 proc 试试。)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mpi.h"
#define ROWS 9
#define COLS 10
int main(int argc, char *argv[]) {
int size_mpi, rank_mpi, row_mpi, col_mpi;
int i,j,p,ttlcols;
int sizes[]= {2*ROWS,2*COLS};
int subsizes[]= {ROWS,COLS};
int starts[] = {0,0};
int vals[ROWS][COLS];
char hdr[] = "This is just a header.\n";
MPI_Status stat_mpi;
MPI_Datatype subarray;
MPI_File fh;
MPI_Offset offset, end_of_hdr;
MPI_Info info_mpi;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&size_mpi);
MPI_Comm_rank(MPI_COMM_WORLD,&rank_mpi);
ttlcols = 2*COLS;
/* Where are we in the array of processes? */
col_mpi = rank_mpi%2;
row_mpi = rank_mpi/2;
/* Populate the array */
for (j=0; j<ROWS; j++){
for (i=0; i<COLS; i++){
vals[j][i] = ttlcols*(ROWS*row_mpi + j) +
COLS*col_mpi + i;
}
}
/* MPI derived datatype for setting a file view */
starts[0] = row_mpi*ROWS;
starts[1] = col_mpi*COLS;
MPI_Type_create_subarray(2, sizes, subsizes, starts,
MPI_ORDER_C, MPI_INT,
&subarray);
MPI_Type_commit(&subarray);
/* open the file */
printf("opening file\n");
MPI_File_open(MPI_COMM_WORLD, "arrdata.dat",
MPI_MODE_WRONLY | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh);
printf("opened file\n");
/* set the initial file view */
MPI_File_set_view(fh, 0, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
/* proc 0 writes first header */
if (rank_mpi == 0) {
MPI_File_write(fh, (void*)hdr, strlen(hdr), MPI_CHAR, &stat_mpi);
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
}
/* everybody has to know where proc 0 stopped writing */
MPI_Bcast((void*)&end_of_hdr, 1, MPI_INT, 0, MPI_COMM_WORLD);
/* re-set file view for writing first array */
MPI_File_set_view(fh, end_of_hdr, MPI_INT,
subarray, "native",
MPI_INFO_NULL);
/* and write the array */
MPI_File_write(fh, (void*)vals, ROWS*COLS, MPI_INT,
&stat_mpi);
/* now go through the whole thing again to test */
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
MPI_File_set_view(fh, end_of_hdr, MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
if (rank_mpi == 0) {
MPI_File_write(fh, (void*)hdr, strlen(hdr), MPI_CHAR, &stat_mpi);
MPI_File_get_position(fh, &offset);
MPI_File_get_byte_offset(fh, offset, &end_of_hdr);
}
MPI_Bcast((void*)&end_of_hdr, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_File_set_view(fh, end_of_hdr, MPI_INT,
subarray, "native",
MPI_INFO_NULL);
MPI_File_write(fh, (void*)vals, ROWS*COLS, MPI_INT,
&stat_mpi);
MPI_File_close(&fh);
MPI_Finalize();
return 0;
}
您的方法很好,如果您现在需要一些东西来将位放入文件中,请继续并完成任务。
这里有一些提高效率的建议:
您可以查询状态对象以了解写入了多少字节,而不是获取位置并转换为字节。
如果您有足够的内存在写入之前保存所有数据,则可以使用 MPI 数据类型来描述您的 I/O(无可否认,创建这种数据类型可能会很痛苦) ).然后所有进程将发出一个单一的集体调用。
你应该使用集体I/O而不是独立I/O。 "quality library" 应该能够为您提供相同甚至更好的性能(如果不能,您可以通过 MPI 实现提出问题)。
如果进程有不同数量的数据要写入,MPI_EXSCAN 是收集谁有什么数据的好方法。然后你可以调用 MPI_FILE_WRITE_AT_ALL 到文件中的正确偏移量。