2016-03-14 93 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