探究多个MPI进程共享同一个文件的行为

NOTICE:

(1)MPI主要运行在集群环境中,但本实验条件有限,只有一台主机,因此实验不是很顺利

(2)实际上GekkoFS的工作原理是对POSIX-I/O接口进行拦截并对POSIX-I/O进行自己的实现,MPI-I/O在HPC I/O栈中位于POSIX-I/O的上层,最终还是会调用POSIX-I/O,因此不必太关注MPI-I/O接口的行为,GekkoFS只需要正确实现POSIX-I/O的语义。

(3)许多传统的HPC应用使用的是POSIX-I/O,如果GKFS不支持POSIX-I/O的接口,那么所有这些传统应用都无法使用GKFS,除非它们修改代码。

N-1模式:多个进程打开同一个文件shared_file.txt

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include<memory.h>

int main(int argc, char *argv[]) {
    int rank, size;
    MPI_File fh;           // MPI文件句柄
    char data[100];        // 要写入的数据
    memset(data, '0', sizeof(data));    //先对缓冲区进行初始化,否则缓冲区中的数据是未定义的,将缓冲区的数据写入到文件中将会得到一串乱码

    // 初始化MPI环境
    MPI_Init(&argc, &argv);
    // 获取进程的编号和总的进程数
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // 打开文件进行并行写入
    int rc = MPI_File_open(MPI_COMM_WORLD, "shared_file.txt", MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
    if (rc != MPI_SUCCESS) {
        // 错误处理
        char error_string[MPI_MAX_ERROR_STRING];
        int length_of_error_string;
        MPI_Error_string(rc, error_string, &length_of_error_string);
        fprintf(stderr, "Error occurred during MPI_File_open: %s\n", error_string);
        MPI_Abort(MPI_COMM_WORLD, rc);
    }
    else{
        //一个共享的文件将被多个进程打开
        printf("Process %d has opened the shared file.\n", rank);
    }
    // 每个进程准备要写入的数据
    sprintf(data, "Process %d writes this line.\n", rank);
    printf("Process %d: %s", rank, data);

    // 每个进程写入自己的数据到文件中的不同位置
    MPI_Offset offset = rank * sizeof(data);
    MPI_File_write_at(fh, offset, data, sizeof(data), MPI_CHAR, MPI_STATUS_IGNORE);

    /*

    //这里每个进程都从文件偏移位置0处,也即从文件的开头处写入数据
    //程序运行结束后,文件中保存的数据属于最后一个被调度运行的进程,其他进程的数据都会被覆盖
    MPI_File_write(fh, data, sizeof(data), MPI_CHAR, MPI_STATUS_IGNORE);

    */
    

    // 关闭文件
    MPI_File_close(&fh);

    // 清理MPI环境
    MPI_Finalize();

    return 0;
}

这里写入文件时使用的接口是MPI_File_write_at(),该接口指定文件写入的位置。使用该接口,可以将一个共享文件划分为多个不相重叠的区域,每个进程有一个rank,根据每个进程的rank计算出该进程负责哪个区域,这样,即使各个进程写文件的时间可能是乱序的不受控制的,但是每个进程写的位置却是固定的,因此最终得到的文件,其内容会符合预期。(谨慎使用MPI_FILE_write())

将以上源文件编译为a.out可执行文件并运行。此处启动4个进程:

yixin@yixin:~/source/mpi$ mpirun -np 4 ./a.out 
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Process 0 has opened the shared file.
Process 0: Process 0 writes this line.
Process 1 has opened the shared file.
Process 1: Process 1 writes this line.
Process 2 has opened the shared file.
Process 2: Process 2 writes this line.
Process 3 has opened the shared file.
Process 3: Process 3 writes this line.

打开shared_file.txt,查看运行结果:

存在问题:

(1) Authorization required, but no authorization protocol specified为每个进程输出的错误信息。似乎是MPI的配置有问题,也许在物理集群中运行就不会报错了?

(2)从终端的输出来看,几个进程似乎并没有并行,而是串行地按照进程rank的大小,先后执行。

N-N模式:每个进程独占一个私有文件,每个进程通过自己的rank来唯一标识并创建自己的文件。

扩展:在MPI程序中,进程的rank有什么重要意义?

在MPI(Message Passing Interface)程序中,每个进程都有一个唯一的标识符,称为进程的秩(rank)。进程的秩在整个MPI程序中扮演着关键角色,具有以下重要意义:

  1. 并行计算中的唯一标识:在并行计算中,多个进程共同执行任务。每个进程的秩是它在MPI进程组中的唯一标识,类似于网络中的IP地址或计算机中的MAC地址。

  2. 进程间的通信:MPI提供了多种通信原语,如MPI_SendMPI_Recv,这些原语允许进程之间交换数据。进程的秩用于指定数据发送给哪个进程或接收哪个进程的数据。

  3. 进程间协作:在并行程序中,进程可能需要协作完成任务,如数据收集、数据分发等。进程的秩有助于确定进程间的协作顺序和方式。

  4. 数据划分:在某些并行算法中,数据可能被划分成多个部分,每个进程处理一部分。进程的秩可以帮助确定每个进程负责处理的数据部分。

  5. 并行程序的调试和分析:在调试和分析并行程序时,进程的秩可以帮助定位问题所在,因为每个进程的行为和结果都可能不同。

  6. 性能优化:在某些情况下,进程的秩可以用于优化性能,例如,在数据划分时,可以选择将相邻的数据分配给相邻的进程,以减少通信开销。

在MPI程序中,进程的秩是一个基本的概念,它贯穿于程序的整个执行过程中,对于程序的正确运行和性能优化都至关重要。因此,理解进程的秩对于编写和分析MPI程序至关重要

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

int main(int argc, char *argv[]) {
    int rank, size;
    MPI_File fh;           // MPI文件句柄
    char data[100];        // 要写入的数据
    char filename[256];    // 文件名

    // 初始化MPI环境
    MPI_Init(&argc, &argv);
    // 获取进程的编号和总的进程数
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // 构造唯一的文件名
    sprintf(filename, "shared_file_%d.txt", rank);

    // 打开文件进行并行写入
    int rc = MPI_File_open(MPI_COMM_WORLD, filename, MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
    //rc = MPI_File_open(MPI_COMM_WORLD, "aaa.txt", MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
    if (rc != MPI_SUCCESS) {
        // 错误处理
        char error_string[MPI_MAX_ERROR_STRING];
        int length_of_error_string;
        MPI_Error_string(rc, error_string, &length_of_error_string);
        fprintf(stderr, "Error occurred during MPI_File_open: %s\n", error_string);
        MPI_Abort(MPI_COMM_WORLD, rc);
    }
    else{
        printf("Process %d has opened an inclusive file.\n", rank);
    }

    // 每个进程准备要写入的数据
    sprintf(data, "Process %d writes this line.\n", rank);

    // 写入数据(这里每个进程都从文件偏移位置为0,也即文件的开头处写入数据,因此文件中最后保存的数据属于最后一个被调度运行的进程)
    MPI_File_write(fh, data, sizeof(data), MPI_CHAR, MPI_STATUS_IGNORE);

    // 关闭文件
    MPI_File_close(&fh);

    // 清理MPI环境
    MPI_Finalize();

    return 0;
}

以上源码编译后启动4个进程运行。运行失败:

yixin@yixin:~/source/mpi$ mpirun -np 4 ./a.out
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
Authorization required, but no authorization protocol specified
hello world!
hello world!
hello world!
hello world!
MPI initianized!
Process 1 has created a file named inclusive_file_1.txt.
MPI initianized!
Process 3 has created a file named inclusive_file_3.txt.
MPI initianized!
MPI initianized!
Process 2 has created a file named inclusive_file_2.txt.
Process 0 has created a file named inclusive_file_0.txt.
Error occurred during MPI_File_open: File does not exist, error stack:
ADIOI_UFS_OPEN(37): File inclusive_file_2.txt does not exist
Abort(670608421) on node 2 (rank 2 in comm 0): application called MPI_Abort(MPI_COMM_WORLD, 670608421) - process 2
Error occurred during MPI_File_open: File does not exist, error stack:
ADIOI_UFS_OPEN(37): File inclusive_file_3.txt does not exist
Abort(737717285) on node 3 (rank 3 in comm 0): application called MPI_Abort(MPI_COMM_WORLD, 737717285) - process 3
Error occurred during MPI_File_open: Other I/O error , error stack:
ADIO_OPEN(223): open failed on a remote node
Abort(536037664) on node 0 (rank 0 in comm 0): application called MPI_Abort(MPI_COMM_WORLD, 536037664) - process 0
Error occurred during MPI_File_open: File does not exist, error stack:
ADIOI_UFS_OPEN(37): File inclusive_file_1.txt does not exist
Abort(603499557) on node 1 (rank 1 in comm 0): application called MPI_Abort(MPI_COMM_WORLD, 603499557) - process 1

存在问题:

(1)只有一台主机,怎么跑出来这么多个node?

(2)为什么文件创建失败?在本实验的N-1模式中文件都可以成功创建,怎么这里就不行了?

手动创建了四个相应的文件,再次启动4个进程:

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值