2016-03-14 58 views
1

我正在进行数值模拟过程之间的大型矢量通信。一切都很好,直到某个时间步骤。我没有收到错误,但输出解决方案显然不正确。MPI全部到全部通信问题

我现在正在调试相当长的一段时间,我的假设是,有在MPI通信错误。

我的代码的通信部分看起来像这样:

MPI_Request req; 
for(int j=0;j<numProcs;j++){ 
    if(j!=myId){ 
     tag=0; 
     sizeToSend=toProc[j].size(); 
     MPI_Isend(&sizeToSend, 1, MPI_LONG_LONG, j, tag, MPI_COMM_WORLD,&req); 
     MPI_Request_free(&req); 
    } 
} 
for(int j=0;j<numProcs;j++){ 
    if(j!=myId){ 
     tag=0; 
     MPI_Recv(&sizeToReceive[j], 1, MPI_LONG_LONG, j, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
    } 
} 
for(int j=0;j<numProcs;j++){ 
    if(j!=myId){ 
     if(toProc[j].size()>0){ 
      tag=1; 
      MPI_Isend(&toProc[j][0], toProc[j].size(), MPI_LONG_LONG, j, tag, MPI_COMM_WORLD,&req); 
      MPI_Request_free(&req); 
     } 
    } 
} 
for(int j=0;j<numProcs;j++){ 
    if(j!=myId){ 
     if(sizeToReceive[j]>0){ 
      receiveBuffer.resize(sizeToReceive[j]); 
      tag=1; 
      MPI_Recv(&receiveBuffer[0], sizeToReceive[j], MPI_LONG_LONG, j, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
      for(int k=0;k<sizeToReceive[j];k++){ 
       domain.field[receiveBuffer[k]]=1; 
      } 
      receiveBuffer.clear(); 
     } 
    } 
} 
MPI_Barrier(MPI_COMM_WORLD); 
for(int j=0;j<toProc.size();j++){ 
    toProc[j].clear(); 
} 

可变numProcs是包含的进程数的int,myId是包含进程的秩的int,tag是int,domain.field是一个vector<char>。 其他必要的变量的定义是这样的:

vector<vector <long long> > toProc; 
toProc.resize(numProcs); 
long long sizeToReceive[numProcs]; 
long long sizeToSend=0; 
vector<long long> receiveBuffer; 

我试图在上面的代码做的就是发送向量toProc[j]id==j for j=0,...,numProcs-1, j!=myId上的每个进程来处理。 为了达到这个目的,我在前两个for-loop中发送和接收这些向量的大小,并在第3个和第4个for循环中发送和接收实际数据。我正在使用Isend,因为我显然希望这些调用是非阻塞的。

toProc[j]中的值是在进程j的向量domain.field(每个进程都有自己的domain.field)中必须设置为1的索引。

我的问题是: 你看到意外的行为任何潜在的在我的Isend-RECV政策的使用。

+1

我没有看到立即的问题,除了垃圾邮件也许太多正在进行的请求,但似乎你可以大大简化并通过'MPI_Alltoall'和'MPI_Alltoallv'加快整个操作。 – Zulan

+0

感谢您的建议,我会尝试使用'MPI_Alltoall'实现相同的行为,您会考虑多少个请求太多?如果我只使用4个进程,那么错误也会发生,可能已经太多了吗? – Jonas

+0

似乎我忽略了一个非常明显的问题,请参阅我的答案。 – Zulan

回答

2

要重复使用一个变量多ISend请求,而不等待完成。

MPI Standard:3.7.2 3.7.4和大约MPI_Request_free

甲非阻塞发送呼叫指示该系统可以开始复制 数据从发送缓冲区的。在调用非阻塞发送操作之后,发送方不应修改发送缓冲区的任何部分 ,直到发送完成为 。

这意味着,在发送完成之前,您不能覆盖sizeToSend

将请求对象标记为释放并将请求设置为 MPI_REQUEST_NULL。与 请求相关的正在进行的通信将被允许完成。该请求仅在其完成后才会被解除分配给 。

这意味着,发送不保证在MPI_Request_free之后完成。

您可以重构您的代码以将sizeToSend保留在向量中,并且也可以将打开的请求保留在向量中以正确地MPI_Waitall。但我建议在整个操作中只使用MPI_AlltoallMPI_Alltoallv

+0

感谢您的建议,我按照您的建议实施了沟通。它不能解决我的问题,但至少我现在有同步通信,并且我可以假设该错误必须在其他地方。 – Jonas

+0

@Jonas如果你可以通过一个小例子重现另一个问题,可以自由地打开另一个问题。您也可以尝试[必须](https://doc.itc.rwth-aachen.de/display/CCP/Project+MUST) - 它是一个MPI正确性检查器。 – Zulan

+0

我发现我的错误,它与MPI没有任何关系......它在'domain.field [receiveBuffer [k]] = 1;'行中,需要区分'receiveBuffer [k]'的情况。但是我只能找到它,因为我使用MPI_Alltoall建议略微改变了这个部分,结果发现错误是不同的。所以,虽然你的建议没有指出我正在寻找的实际错误,但它帮助我们检测到了很多(并改进了我的代码)。所以再次感谢你,使命完成:) – Jonas