首页 > 解决方案 > 我可以将两个单独的可执行文件与 MPI_open_port 链接并在文本文件中共享端口信息吗?

问题描述

我正在尝试MPI COMM在两个独立启动的可执行文件之间创建共享,例如

mpiexec -n 1 ./exe1 
mpiexec -n 1 ./exe2

我使用MPI_Open_port生成端口详细信息并将它们写入 exe1 中的文件,然后使用 exe2 读取。这之后是MPI_Comm_connect/ MPI_Comm_accept,然后是发送/接收通信(下面的最小示例)。

我的问题是:我们可以以这种方式将端口信息写入文件,还是MPI_Publish_name/MPI_Lookup_nameMPI 需要像thisthisthis那样工作?由于超级计算机通常共享一个文件系统,这种基于文件的方法似乎更简单,并且可能避免建立服务器。

看来这应该根据MPI 3.1 标准MPI_Open_Port中的文档工作,

port_name 本质上是一个网络地址。它在它所属的通信域中是唯一的(由实现确定),并且可以由该通信域中的任何客户端使用。例如,如果它是一个互联网(主机:端口)地址,它将在互联网上是唯一的。如果它是 IBM SP 上的低级开关地址,那么它将对该 SP 唯一

此外,根据MPI 论坛上的文档:

将端口信息写入文件确实按预期工作,即创建共享通信器并使用 MPICH (3.2) 交换信息,但在使用 OpenMPI 版本 2.0.1 和 4.0.1 时挂在MPI_Comm_connect/行(在我的本地工作站上运行 Ubuntu 12.04 但MPI_Comm_accept最终需要在 1 级超级计算机上工作)。我在这里提出了一个问题,但同时欢迎解决方案或解决方法。

更多信息

如果我在 OpenMPI 中使用 MPMD 模式,

mpiexec -n 1 ./exe1 : -n 1 ./exe2

ompi_global_scope这可以正常工作,因此在问题中允许共享工作肯定是个问题。我也试过添加,

MPI_Info info;
MPI_Info_create(&info);
MPI_Info_set(info, "ompi_global_scope", "true");

将信息传递给所有命令,但没有成功。我没有运行服务器/客户端模型,因为两个代码同时运行,因此共享一个 URL/PID 并不理想,尽管即使使用建议的方法(对于 OpenMPI 2.0.1,我也无法使其工作),

mpirun -n 1 --report-pid + ./OpenMPI_2.0.1 0
1234

mpirun -n 1 --ompi-server pid:1234 ./OpenMPI_2.0.1 1

给,

ORTE_ERROR_LOG: Bad parameter in file base/rml_base_contact.c at line 161

This failure appears to be an internal failure;
here's some additional information (which may only be relevant to an
Open MPI developer):

  pmix server init failed
  --> Returned value Bad parameter (-5) instead of ORTE_SUCCESS

使用 OpenMPI 4.0.1,

mpirun -n 1 --report-pid + ./OpenMPI_4.0.1 0
1234

mpirun -n 1 --ompi-server pid:1234 ./OpenMPI_4.0.1 1

给,

ORTE_ERROR_LOG: Bad parameter in file base/rml_base_contact.c at line 50

...

A publish/lookup server was provided, but we were unable to connect
to it - please check the connection info and ensure the server
is alive:

使用 4.0.1 意味着该错误不应与OpenMPI中的此错误有关。

最少的代码

    #include "mpi.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <iostream>
    #include <fstream>

    using namespace std;

    int main( int argc, char *argv[] )
    {
        int num_errors = 0;
        int rank, size;
        char port1[MPI_MAX_PORT_NAME];
        char port2[MPI_MAX_PORT_NAME];
        MPI_Status status;
        MPI_Comm comm1, comm2;
        int data = 0;

        char *ptr;
        int runno = strtol(argv[1], &ptr, 10);
        for (int i = 0; i < argc; ++i)
            printf("inputs %d %d %s \n", i,runno, argv[i]);

        MPI_Init(&argc, &argv);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);

        if (runno == 0)
        {
            printf("0: opening ports.\n");fflush(stdout);
            MPI_Open_port(MPI_INFO_NULL, port1);
            printf("opened port1: <%s>\n", port1);

            //Write port file
            ofstream myfile;
            myfile.open("port");
            if( !myfile )
                    cout << "Opening file failed" << endl;
            myfile << port1 << endl;
            if( !myfile )
                cout << "Write failed" << endl;
            myfile.close();

            printf("Port %s written to file \n", port1); fflush(stdout);

            printf("Attempt to accept port1.\n");fflush(stdout);

            //Establish connection and send data
            MPI_Comm_accept(port1, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &comm1);

            printf("sending 5 \n");fflush(stdout);
            data = 5;
            MPI_Send(&data, 1, MPI_INT, 0, 0, comm1);
            MPI_Close_port(port1);
        }
        else if (runno == 1)
        {

            //Read port file
            size_t   chars_read = 0;  
            ifstream myfile;
            //Wait until file exists and is avaialble
            myfile.open("port");
            while(!myfile){
                myfile.open("port");
                cout << "Opening file failed" << myfile << endl;
                usleep(30000);
            }
            while( myfile && chars_read < 255 ) {
                myfile >> port1[ chars_read ];    
                if( myfile ) 
                     ++chars_read; 

                if( port1[ chars_read - 1 ] == '\n' ) 
                     break;
            }
            printf("Reading port %s from file \n", port1); fflush(stdout);
            remove( "port" );

            //Establish connection and recieve data
            MPI_Comm_connect(port1, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &comm1);
            MPI_Recv(&data, 1, MPI_INT, 0, 0, comm1, &status);
            printf("Received %d 1\n", data); fflush(stdout);

        }

        //Barrier on intercomm before disconnecting
        MPI_Barrier(comm1);
        MPI_Comm_disconnect(&comm1);
        MPI_Finalize();
        return 0;
    }

在上面的示例中,0 和 1 只是指定此代码是写入端口文件还是读取它。然后运行,

mpiexec -n 1 ./a.out 0 
mpiexec -n 1 ./a.out 1

标签: mpiopenmpi

解决方案


推荐阅读