簡體   English   中英

MPI_Allgather中的奇怪死鎖

[英]Bizarre deadlock in MPI_Allgather

經過大量的谷歌搜索,我不知道是什么導致了這個問題。 這里是:

我在我的代碼中有一個簡單的MPI_Allgather調用,我有雙重,三重和四重檢查是正確的(發送/接收緩沖區大小合適;調用中的發送/接收大小是正確的),但對於“大”進程數我得到死鎖或MPI_ERR_TRUNCATE。 使用MPI_Comm_split將用於Allgather的通信器與MPI_COMM_WORLD分開。 對於我目前的測試,等級0進入一個通信器,其余等級進入第二個通信器。 總共6個或更少,Allgather工作得很好。 如果我使用7個等級,我會得到一個MPI_ERR_TRUNCATE。 8級,僵局。 我已經驗證通信器被正確分割(兩個通信的所有等級的MPI_Comm_rank和MPI_Comm_size都是正確的)。

我手動驗證了每個發送和接收緩沖區的大小,以及最大接收數。 我的第一個解決方法是將MPI_Allgather交換為MPI_Gather的for循環到每個進程。 這適用於這種情況,但更改給我的代碼的網格(使用METIS划分的CFD網格)帶來了問題。 現在我的解決方案,我還沒有打破(還),用Allgatherv取代Allgather ,我認為無論如何它更有效,因為我從每個進程發送了不同數量的數據。

這是(我希望)在上下文中相關的違規代碼; 如果我錯過了什么,有問題的Allgather就在這個文件的第599行。

  // Get the number of mpiFaces on each processor (for later communication)
  // 'nProgGrid' is the size of the communicator 'gridComm'
  vector<int> nMpiFaces_proc(nProcGrid);

  // This MPI_Allgather works just fine, every time      
  // int nMpiFaces is assigned on preceding lines
  MPI_Allgather(&nMpiFaces,1,MPI_INT,nMpiFaces_proc.data(),1,MPI_INT,gridComm);

  int maxNodesPerFace = (nDims==2) ? 2 : 4;
  int maxNMpiFaces = getMax(nMpiFaces_proc);
  // The matrix class is just a fancy wrapper around std::vector that 
  // allows for (i,j) indexing.  The getSize() and getData() methods just
  // call the size() and data() methods, respectively, of the underlying
  // vector<int> object.
  matrix<int> mpiFaceNodes_proc(nProcGrid,maxNMpiFaces*maxNodesPerFace);
  // This is the MPI_Allgather which (sometimes) doesn't work.
  // vector<int> mpiFaceNodes is assigned in preceding lines
  MPI_Allgather(mpiFaceNodes.data(),mpiFaceNodes.size(),MPI_INT,
                mpiFaceNodes_proc.getData(),maxNMpiFaces*maxNodesPerFace,
                MPI_INT,gridComm);

我目前正在使用OpenMPI 1.6.4,g ++ 4.9.2和帶有16GB RAM的AMD FX-8350 8核處理器,運行Elementary OS Freya 0.3(基本上是Ubuntu 14.04)的最新更新。 但是,我在使用CentOS,Intel硬件和MPICH2的另一台機器上也遇到了這個問題。

有任何想法嗎? 我聽說可以更改MPI的內部緩沖區大小來修復類似的問題,但是很快就會嘗試這樣做(如http://www.caps.ou.edu/pipermail/arpssupport/2002中所示) -May / 000361.html )沒有效果。

作為參考,這個問題非常類似於這里顯示的問題: https//software.intel.com/en-us/forums/topic/285074 ,除了在我的情況下,我只有1個處理器,8個核心,在一台台式電腦。

更新我已經設法將這個失敗的極簡主義例子放在一起:

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>

#include "mpi.h"

using namespace std;

int main(int argc, char* argv[])
{
  MPI_Init(&argc,&argv);

  int rank, nproc, newID, newRank, newSize;
  MPI_Comm newComm;
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  MPI_Comm_size(MPI_COMM_WORLD,&nproc);

  newID = rank%2;
  MPI_Comm_split(MPI_COMM_WORLD,newID,rank,&newComm);
  MPI_Comm_rank(newComm,&newRank);
  MPI_Comm_size(newComm,&newSize);

  srand(time(NULL));

  // Get a different 'random' number for each rank on newComm
  //int nSend = rand()%10000;
  //for (int i=0; i<newRank; i++) nSend = rand()%10000;

  /*! -- Found a set of #'s which fail for nproc=8: -- */
  int badSizes[4] = {2695,7045,4256,8745};
  int nSend = badSizes[newRank];

  cout << "Comm " << newID << ", rank " << newRank << ": nSend = " << nSend << endl;

  vector<int> send(nSend);
  for (int i=0; i<nSend; i++) 
    send[i] = rand();

  vector<int> nRecv(newSize);
  MPI_Allgather(&nSend,1,MPI_INT,nRecv.data(),1,MPI_INT,newComm);

  int maxNRecv = 0;
  for (int i=0; i<newSize; i++)
    maxNRecv = max(maxNRecv,nRecv[i]);

  vector<int> recv(newSize*maxNRecv);
  MPI_Barrier(MPI_COMM_WORLD);
  cout << "rank " << rank << ": Allgather-ing data for communicator " << newID << endl;
  MPI_Allgather(send.data(),nSend,MPI_INT,recv.data(),maxNRecv,MPI_INT,newComm);
  cout << "rank " << rank << ": Done Allgathering-data for communicator " << newID << endl;

  MPI_Finalize();
  return 0;
}

上面的代碼編譯並運行為:

mpicxx -std=c++11 mpiTest.cpp -o mpitest
mpirun -np 8 ./mpitest

在我的16核CentOS和我的8核Ubuntu機器上輸出以下輸出:

Comm 0, rank 0: nSend = 2695
Comm 1, rank 0: nSend = 2695
Comm 0, rank 1: nSend = 7045
Comm 1, rank 1: nSend = 7045
Comm 0, rank 2: nSend = 4256
Comm 1, rank 2: nSend = 4256
Comm 0, rank 3: nSend = 8745
Comm 1, rank 3: nSend = 8745
rank 5: Allgather-ing data for communicator 1
rank 6: Allgather-ing data for communicator 0
rank 7: Allgather-ing data for communicator 1
rank 0: Allgather-ing data for communicator 0
rank 1: Allgather-ing data for communicator 1
rank 2: Allgather-ing data for communicator 0
rank 3: Allgather-ing data for communicator 1
rank 4: Allgather-ing data for communicator 0
rank 5: Done Allgathering-data for communicator 1
rank 3: Done Allgathering-data for communicator 1
rank 4: Done Allgathering-data for communicator 0
rank 2: Done Allgathering-data for communicator 0

請注意,每個通信器中只有2個隊列退出Allgather; 這不是我的實際代碼中發生的事情('破碎'通信器上的排名沒有退出Allgather),但最終結果是相同的 - 代碼掛起直到我殺了它。

我猜這與每個進程的發送數量不同有關,但據我所知,從我看過的MPI文檔和教程中,這應該是允許的,這是正確的嗎? 當然,MPI_Allgatherv更適用,但為了簡單起見,我一直在使用Allgather。

如果輸入計數在所有進程中不相同,則必須使用MPI_Allgatherv

確切地說,必須匹配的是類型簽名count,type ,因為從技術上講,您可以使用不同的數據類型獲得相同的基本表示(例如,N個元素與1個元素是N個元素的連續類型),但是如果使用到處都是相同的論點,這是MPI集體的常見用法,那么你的計數必須在任何地方都能匹配。

最新MPI標准(3.1)的相關部分位於第165頁:

在進程中與sendcount,sendtype關聯的類型簽名必須等於與recvcount相關聯的類型簽名,在任何其他進程中都是recvtype。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM