如何解决使用多个 MPI 进程并发非重叠 pwrite() 到挂载在 NFS 上的文件
我有一个计算流体动态代码,我正在编写并行读写实现。我想要实现的是多个 MPI 进程打开同一个文件并向其写入数据(没有数据重叠,我使用带有偏移信息的 pwrite())。当两个 MPI 进程在同一个计算节点上时,这似乎工作正常。但是,当我使用 2 个或更多计算节点时,部分数据无法到达硬盘。为了证明这一点,我编写了以下使用 mpicc 编译的 C 程序(我的 MPI 发行版是 MPICH):
#include <mpi.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
long _numbering(long i,long j,long k,long N) {
return (((i-1)*N+(j-1))*N+(k-1));
}
int main(int argc,char **argv)
{
int numranks,rank,fd,dd;
long i,j,k,offset,N;
double value=1.0;
MPI_Init(NULL,NULL);
MPI_Comm_size(MPI_COMM_WORLD,&numranks);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
N=10;
offset=rank*N*N*N*sizeof(double);
fd=-1;
printf("opening file datasetparallel.dat\n");
//while(fd==-1) {fd = open("datasetparallel.dat",O_RDWR | O_CREAT | O_SYNC,0666);}
while(fd==-1) {fd = open("datasetparallel.dat",O_RDWR | O_CREAT,0666);}
//while(dd==-1) {fd = open("/homeA/Desktop/",O_RDWR,0666);}
for(i=1;i<=N;i++) {
for(j=1;j<=N;j++) {
for(k=1;k<=N;k++) {
if(pwrite(fd,&value,sizeof(double),_numbering(i,N)*sizeof(double)+offset)!=8) perror("datasetparallel.dat");
//pwrite(fd,N)*sizeof(double)+offset);
value=value+1.0;
}
}
}
//if(close(fd)==-1) perror("datasetparallel.dat");
fsync(fd); //fsync(dd);
close(fd); //close(dd);
printf("Done writing in parallel\n");
if(rank==0) {
printf("Beginning serial write\n");
int ranknum;
fd=-1;
value=1.0;
while(fd==-1) {fd = open("datasetserial.dat",0666);}
for(ranknum=0;ranknum<numranks;ranknum++){
offset=ranknum*N*N*N*sizeof(double); printf("Offset for rank %d is %ld\n",ranknum,offset);
printf("writing for rank=%d\n",ranknum);
for(i=1;i<=N;i++) {
for(j=1;j<=N;j++) {
for(k=1;k<=N;k++) {
if(pwrite(fd,N)*sizeof(double)+offset)!=8) perror("datasetserial.dat");
//pwrite(fd,N)*sizeof(double)+offset);
value=value+1.0;
}
}
}
value=1.0;
}
//if(close(fd)==-1) perror("datasetserial.dat");
fsync(fd);
close(fd);
printf("Done writing in serial\n");
}
MPI_Finalize();
return 0;
}
上述程序以升序将双精度数写入文件。每个 MPI 进程写入相同的数字(1.0 到 1000.0),但写入文件的不同区域。例如,rank 0 将 1.0 写入 1000.0,而 rank 1 从 rank 0 写入 1000.0 之后的位置开始写入 1.0 至 1000.0。该程序输出一个名为 datasetparallel.dat 的文件,该文件已通过并发 pwrite()s 写入。它还输出 datasetserial.dat 以供参考以与 datasetparallel.dat 文件进行比较以检查其完整性(我通过在终端中使用 cmp 命令来执行此操作)。当使用 cmp 发现差异时,我使用 od 命令检查文件的内容:
od -N <byte_number> -tfD <file_name>
例如,我使用上述程序发现了一些丢失的数据(文件中的漏洞)。在并行写入的文件中,使用od
命令的输出:
.
.
.
0007660 503 504
0007700 505 506
0007720 507 508
0007740 509 510
0007760 511 512
0010000 0 0
*
0010620 0
0010624
.
.
.
0007760 511 512
0010000 513 514
0010020 515 516
0010040 517 518
0010060 519 520
0010100 521 522
0010120 523 524
0010140 525 526
0010160 527 528
0010200 529 530
0010220 531 532
0010240 533 534
0010260 535 536
0010300 537 538
0010320 539 540
0010340 541 542
0010360 543 544
0010400 545 546
0010420 547 548
0010440 549 550
0010460 551 552
0010500 553 554
0010520 555 556
0010540 557 558
0010560 559 560
0010600 561 562
0010620 563 564
.
.
.
到目前为止,解决此问题的唯一方法似乎是使用带有 O_SYNC 标志的 POSIX open() 函数,以确保将文件物理写入硬盘驱动器,但这似乎慢得不切实际。另一种同样缓慢的方法似乎是使用内置的 MPI I/O 命令。我不确定为什么 MPI I/O 也很慢。存储已使用以下标志挂载在 NFS 上: rw,nohide,insecure,no_subtree_check,sync,no_wdelay
。我尝试在文件和目录上调用 fsync() 无济于事。因此,我需要有关如何解决此问题的建议。
解决方法
NFS 是一个可怕的文件系统。正如您所见,它的缓存行为使进程“错误地共享”缓存块然后破坏数据变得非常容易。
如果您坚持使用 NFS,请并行执行计算,然后从一个级别执行所有 I/O。
真正的并行系统,如 OrangeFS/PVFS (http://www.orangefs.org) 在这里会大有帮助,尤其是在开始使用 MPI-IO 时(您已经在使用 MPI,所以您已经成功了一半!)。光泽是另一种选择。 OrangeFS 是两者中配置更简单的一个,但我可能有偏见,因为我曾经在它上面工作过。
在集体 I/O 中寻址随机内存是绝对可能的。您的所有数据都是 MPI_DOUBLE,因此您需要做的就是描述最差 MPI_TYPE_CREATE_HINDEXED 的区域并提供地址。如果没有其他原因,您将看到性能的巨大提升,而不是发出一个 MPI-IO 调用而不是 (if N == 10) 1000。您的数据在文件中是连续的,因此您甚至不必担心关于文件视图。
此外,请记住我说过“从一个进程执行所有 I/O?”。这有点高级,但是如果您将“cb_nodes”提示(用于“集体缓冲”优化的节点数)设置为 1 MPI-IO,那么您就可以做到这一点。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。