Hi,

I would like to know which of "waitone" vs "waitany" is optimal and of course, will never produce deadlocks.

Let's say we have "lNp" processes and they want to send an array of int of length "lNbInt" to process "0" in a non-blocking MPI_Isend (instead of MPI_Gather). Let's say the order for receiving is unimportant and we want to start using data as soon as possible.

I have attached wait.cc, that one can compile in two manners:

mpicxx -o waitone wait.cc

mpicxx -DMPI_WAIT_ANY_VERSION -o waitany wait.cc

Then launch using 1 parameter to the executable: the length "lNbInt".

The waitone version:
mpirun -display-map -H host1,host2,host3 -n 24 waitone 10000

The waitany version:
mpirun -display-map -H host1,host2,host3 -n 24 waitany 10000

After executing several times, on different number of processes and different number of nodes and almost always large value of "lNbInt", I *think* these could be good conclusions? :

#1- Both version take almost the same wall clock time to complete
#2- Both version do *not* produce deadlock
#3- MPI_WAIT_ANY_VERSION could do better if some work was really done with received data. #4- MPI_WAIT_ANY_VERSION received always the data from processes on the same host.

I haven't be able to reproduce a deadlock even while varying array length, number of processes and number of hosts. How can I conclude there are no problem with this code? Any reading suggestion?

Thanks!

Eric
#include "mpi.h"
#include <iostream>
#include <cstdlib>

//Use the following for the MPI_Waitany version
//#define MPI_WAIT_ANY_VERSION

int main(int pArgc, char *pArgv[])
{
  int lRank = -1;
  int lNp   = -1;
  int lTag = 1;
  int lRet = 0;

  if (pArgc != 2) {
    std::cerr << "Please specify the number of int to send!" << std::endl;
    return 1;
  }
  int lNbInt = std::atoi(pArgv[1]);

  MPI_Request lSendRequest;
  MPI_Status  lStatus;
  lStatus.MPI_ERROR  = MPI_SUCCESS;

  MPI_Init(&pArgc,&pArgv);

  MPI_Comm lComm = MPI_COMM_WORLD;

  MPI_Comm_size(lComm, &lNp);

  MPI_Comm_rank(lComm, &lRank);

  int * lPtrToArrayOfInt = 0;
  int * lVecInt = 0;

  if (lRank != 0 ) {
    lPtrToArrayOfInt = new int[lNbInt];
    for (int i = 0; i< lNbInt; ++i) {
      lPtrToArrayOfInt[i] = rand();
    }
    MPI_Isend(lPtrToArrayOfInt, lNbInt, MPI_INT, 0, lTag, lComm, &lSendRequest);
  }
  else {
    MPI_Request* lVecRequest = new MPI_Request[lNp-1];
    lVecInt = new int[lNbInt*lNp-1];
    if (0 == lVecInt) {
      std::cerr<< "Unable to allocate array!" <<std::endl;
      return 1;
    }
    for (int i = 1; i < lNp  ; ++i) {
      MPI_Irecv(&lVecInt[lNbInt*(i-1)], lNbInt, MPI_INT, i, lTag, lComm, 
&lVecRequest[i-1]);
    }
    //Ok, now Wait for receiving some data and start to process them:
    for (int i = 1; i < lNp ; ++i) {
      lStatus.MPI_ERROR  = MPI_SUCCESS;
#ifndef MPI_WAIT_ANY_VERSION
      MPI_Wait(&lVecRequest[i-1], &lStatus);
      std::cout << "Waited for rank " << i << std::endl;
#else
      int lIndexInVec = -1;
      MPI_Waitany(lNp-1, lVecRequest, &lIndexInVec, &lStatus);
      const int lRankReceived = lIndexInVec+1;
      if (lStatus.MPI_ERROR != MPI_SUCCESS) {
        std::cerr << "Error in MPI_Waitany" << std::endl;
        return 1;
      }
      else {
        std::cout << "Waited for any and received rank " << lRankReceived << 
std::endl;
      }

#endif
      //Do something in the range from lVecInt[100*(lRankReceived-1)] to 
lVecInt[100*(lRankReceived)-1]
      // ...
    }
  }
  // Some other treatments not modifying lPtrToArrayOf100Int
  // ...

  // The end:
  if (lRank != 0 ) {
    MPI_Wait(&lSendRequest, &lStatus);

    delete lPtrToArrayOfInt;
  }
  else  {
    delete lVecInt;
  }

  //std::cout << "rank ["<<lRank << "] has completed! " <<std::endl;

  MPI_Finalize();

  return 0;
}

Reply via email to