mpi - 我可以将两个单独的可执行文件与 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_name
MPI 需要像this、this和this那样工作?由于超级计算机通常共享一个文件系统,这种基于文件的方法似乎更简单,并且可能避免建立服务器。
看来这应该根据MPI 3.1 标准MPI_Open_Port
中的文档工作,
port_name 本质上是一个网络地址。它在它所属的通信域中是唯一的(由实现确定),并且可以由该通信域中的任何客户端使用。例如,如果它是一个互联网(主机:端口)地址,它将在互联网上是唯一的。如果它是 IBM SP 上的低级开关地址,那么它将对该 SP 唯一
此外,根据MPI 论坛上的文档:
以下应该与 MPI 兼容:服务器向终端打印一个地址,用户将此地址提供给客户端程序。
MPI 不需要名称服务器
port_name 是系统提供的字符串,它对可以联系服务器的低级网络地址进行编码。
就其本身而言,port_name 机制是完全可移植的......
将端口信息写入文件确实按预期工作,即创建共享通信器并使用 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
解决方案
推荐阅读
- android - Android计算并着色屏幕的每个像素
- javascript - 用我的 HTML 时钟(-9 小时)格式化中国的时间,同时保持非军事时间?
- javascript - if 语句和 vuejs 重新启动计数器的错误
- javascript - GraphQL 和休眠 (ORM)
- mongodb - 我想根据 Mongo DB 中的匹配条件(ID)将集合(发布)中的几个字段添加到另一个集合(故事)中
- python - 如何确保 Celery 任务在 Pytest 中排队?
- reactjs - 在反应组件中添加多个验证
- python - 如果函数名包含特定字符串,如何在自身内部循环函数并执行其中一些函数
- arrays - 从字典数组中删除重复的字典
- linux - 运行命令,然后通过 SQLCMD 添加结果