C++ 使用MPI_Bcast发送动态大小的动态数组
OpenMPI:我想读取根节点上的文件,并将该文件的内容发送到所有其他节点。 我发现MPI_Bcast可以:C++ 使用MPI_Bcast发送动态大小的动态数组,c++,mpi,C++,Mpi,OpenMPI:我想读取根节点上的文件,并将该文件的内容发送到所有其他节点。 我发现MPI_Bcast可以: int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) 我发现的所有示例都具有已知的count值,但在我的示例中,count值主要是在根上已知的。其他人说,相同的MPI_Bcast调用检索其他节点上的数据 我补充说: typedef short Descript
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,
int root, MPI_Comm comm)
我发现的所有示例都具有已知的count
值,但在我的示例中,count值主要是在根上已知的。其他人说,相同的MPI_Bcast调用检索其他节点上的数据
我补充说:
typedef short Descriptor[128];
MPI_Datatype descriptorType;
MPI_Type_contiguous(sizeof(Descriptor), MPI_SHORT, &descriptorType);
MPI_Type_commit(&descriptorType);
if(world_rank == 0) {
struct stat finfo;
if(stat(argv[1], &finfo) == 0) {
querySize = finfo.st_size/sizeof(Descriptor);
}
{
//read binary query
queryDescriptors = new Descriptor[querySize];
fstream qFile(argv[1], ios::in | ios::binary);
qFile.read((char*)queryDescriptors, querySize*sizeof(Descriptor));
qFile.close();
}
}
MPI_Bcast((void*)&querySize, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (world_rank != 0)
{
queryDescriptors = new Descriptor[querySize];
}
MPI_Bcast((void*)queryDescriptors, querySize, descriptorType, 0, MPI_COMM_WORLD);
当我这样称呼它时:mpirun-np2./mpi\u hello\u world
它工作正常,但当我用超过2的名称来称呼它时,我得到了以下结果:
mpi_hello_world: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
mpi_hello_world: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
如果qFile.read(…)
未包含在If(rank==0){}
测试中,则所有进程都将读取该文件。和queryDescriptors=新描述符[querySize]
应在第一个MPI\u Bcast()之后调用。
对于除0之外的所有进程:querySize
对这些进程没有意义
进程0必须:
- 阅读项目的数量
- 分配
- 读取数组
- 广播项目的数量
- 广播阵列
- 接收项目的数量
- 分配
- 接收阵列
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <mpi.h>
using namespace std;
int main (int argc, char *argv[])
{
int rank;
int size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == 0)
{
//creating the file
ofstream myfile;
myfile.open ("example.txt", ios::out |ios::binary);
int nbitem=42;
myfile.write((char*)&nbitem,sizeof(int));
float a=0;
for(int i=0;i<nbitem;i++){
myfile.write((char*)&a,sizeof(float));
a+=2;
}
myfile.close();
}
//now reading the file
int nbitemread=0;
float* buffer;
if(rank==0){
ifstream file ("example.txt", ios::in |ios::binary);
file.read ((char*)&nbitemread, sizeof(int));
buffer=new float[nbitemread];
file.read ((char*)buffer,nbitemread* sizeof(float));
file.close();
//communication
MPI_Bcast(&nbitemread, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(buffer, nbitemread, MPI_FLOAT, 0, MPI_COMM_WORLD);
}else{
MPI_Bcast(&nbitemread, 1, MPI_INT, 0, MPI_COMM_WORLD);
//nbitemread is meaningfull now
buffer=new float[nbitemread];
MPI_Bcast(buffer, nbitemread, MPI_FLOAT, 0, MPI_COMM_WORLD);
}
//printing...
cout<<"on rank "<<rank<<" rode "<<buffer[nbitemread/2]<<" on position "<<nbitemread/2<<endl;
delete[] buffer;
MPI_Finalize();
return 0;
}
所以发出两个广播,第一个是计数,第二个是缓冲区内容。你是对的,这是一个解决方案。我想知道MPI中是否有一种机制用于这种情况。我不知道,但我的MPI有点生锈了。Mark是对的-唯一的解决方案是使用两个广播。与常规的点对点通信不同,MPI无法提前探测广播消息。事实上,这也适用于所有集合调用,例如,
MPI\u分散
,MPI\u聚集
,等等。我使用了指向的解决方案标记,但由于第二个MPI\u Bcast,我得到了此错误,querySize为23。我在一个节点上工作,这会是一个问题吗?很抱歉没有提及,但我基本上也是这样做的。我使用mpic++和mpirun-np 3 main,我在问题中添加了更多的代码。法兰西万岁!我想知道这是否是一个问题,因为我在单个节点上运行它?Traiasca Romania!这不应该是个问题,除非文件真的很大。因为整个文件都是广播的,所以有和进程一样多的副本(可能更多用于消息传递)。如果您的文件比RAM小20倍,则不会失败。这个比例是多少?此外,如果使用集群,可能需要为作业管理器指定内存需求。因为它可能是#SBATCH--mem1g
。此限制的默认值通常较低,指定更高的值可能会有所帮助。cat/proc/meminfo表示:2052392 kB,文件为:5888字节。我还没有使用集群,只使用mpirun和host参数。
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mpi.h>
using namespace std;
int main (int argc, char *argv[])
{
int world_rank;
int size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int querySize;
typedef short Descriptor[128];
MPI_Datatype descriptorType;
MPI_Type_contiguous(sizeof(Descriptor), MPI_CHAR, &descriptorType);
MPI_Type_commit(&descriptorType);
Descriptor* queryDescriptors;
if(world_rank == 0) {
struct stat finfo;
if(stat(argv[1], &finfo) == 0) {
cout<<"st_size "<<finfo.st_size<<" descriptor "<<sizeof(Descriptor)<< endl;
querySize = finfo.st_size/sizeof(Descriptor);
cout<<"querySize "<<querySize<<endl;
}else{
cout<<"stat error"<<endl;
}
{
//read binary query
queryDescriptors = new Descriptor[querySize];
fstream qFile(argv[1], ios::in | ios::binary);
qFile.read((char*)queryDescriptors, querySize*sizeof(Descriptor));
qFile.close();
}
}
MPI_Bcast((void*)&querySize, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (world_rank != 0)
{
queryDescriptors = new Descriptor[querySize];
}
MPI_Bcast((void*)queryDescriptors, querySize, descriptorType, 0, MPI_COMM_WORLD);
cout<<"on rank "<<world_rank<<" rode "<<queryDescriptors[querySize/2][12]<<" on position "<<querySize/2<<endl;
delete[] queryDescriptors;
MPI_Finalize();
return 0;
}