0
$\begingroup$

I am running a CFD simulation with a 200,000-vertex mesh. I've decomposed the mesh into 2 load-balanced sub-domains to test my parallel implementation. In the specific function that I am time-profiling, each sub-domain has to send a 3D gradient vector of MPI_DOUBLEs for each of the ~2000 vertices that lie on the parallel communication boundary. The vertex list is sorted such that all vertices involved in parallel communication lie at the start of the list (ivertParaCommStart is the parallel vertex in the list with the largest index). The following is a simplified version of my code:

MPI_Request sendRequ; // Local variable in each thread
MPI_Request recvRequ; // Local variable in each thread
for(ivert, mvert)
{
  // Perform costly calculations for each vertex.....

  if(ivert == ivertCommStart)
  {
    // Load data from ALL parallel vertices and communicate with other thread in one go.
    MPI_Isend(..., ..., MPI_DOUBLE, (ithread == 0 ? 1 : 0), ..., ..., &sendRequ);
    MPI_Irecv(..., ..., MPI_DOUBLE, (ithread == 0 ? 1 : 0), ..., ..., &recvRequ);
  }
  else if(ivert > ivertCommStart)
  {
    MPI_Test(&sendRequ, ..., ...);
    MPI_Test(&recvRequ, ..., ...);
  }
}

MPI_Wait(&sendRequ, ...); // Send is still not completed at this point
MPI_Wait(&recvRequ, ...); // Recv is still not completed at this point

Considering that the total number of parallel communication vertices is ~4000 in each sub-domain (~4% of the total number of vertices) and considering the cost of the computations performed for each vertex, I would have expected that the data transfer would be completely masked by the computations performed over the remaining non-parallel vertices. However, this is not the case. Note that after the MPI_Wait calls do eventually return, I have confirmed that the data exchanged is as I would expect (parallel simulations produce equivalent results to a serial simulation). However, the cost of the MPI_Wait() calls yields very poor scaling of my code. Can anyone advise me on why MPI_Test() is not progressing my send and receive requests?

EDIT: Apologies for any confusion caused - I should clarify that I communicate the data for all parallel vertices in one go.

EDIT 2: I have found that the MPI_Test calls do not allow me to overlap the communication and computation. They have a significant overhead. Effectively, the total time for the for loop + MPI_Wait calls is the same as if I wait till the end of the for loop and then communicate the parallel data using blocking send/recv calls (the code below takes the same amount of time to run as the code above). So I am seeing no benefit of the non-blocking communication. I am relatively new to MPI. I would appreciate any advice on what could be going on here.

for(ivert, mvert)
{
  // Perform costly calculations for each vertex.....
}

// Load data from ALL parallel vertices and communicate with other thread.
MPI_Request sendRequ; 
MPI_Request recvRequ;
MPI_Isend(..., ..., MPI_DOUBLE, (ithread == 0 ? 1 : 0), ..., ..., &sendRequ);
MPI_Irecv(..., ..., MPI_DOUBLE, (ithread == 0 ? 1 : 0), ..., ..., &recvRequ);
MPI_Wait(&sendRequ, ...);
MPI_Wait(&recvRequ, ...);
```
$\endgroup$

1 Answer 1

1
$\begingroup$

MPI_Test is a local operation. Do MPI_Iprobe instead. It can also be that your MPI allows you to control asynchronous progress with enviroment variables. Intel MPI does that, I don't know about others.

Things may also depend on your network cards.

$\endgroup$
5
  • $\begingroup$ By "local operation" do you mean that MPI_Test it utilises the specific thread's resources to progress MPI_Isend/MPI_Irecv? $\endgroup$
    – niran90
    Feb 12, 2021 at 14:43
  • $\begingroup$ "local operation" is a technical term in the standard. It means that no interaction with other processes is happening. In particular: it doesn't force progress. $\endgroup$ Feb 12, 2021 at 14:46
  • $\begingroup$ Okay, I see what you mean. I shall try MPI_Iprobe instead. Regarding ensuring computation/communication overlap, does MPI_Iprobe utilise the thread's resources to progress the send/recv. If so, can you advise me (or direct me to a source) on how I can assign a separate thread for the MPI progress engine so that I can achieve overlap? $\endgroup$
    – niran90
    Feb 12, 2021 at 14:51
  • 1
    $\begingroup$ The use of a separate thread for progress is not covered by the standard. MPI implementaitons such as Intel MPI control this through environment variables and such. $\endgroup$ May 17, 2021 at 14:49
  • 1
    $\begingroup$ int flag; MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, MPI_STATUS_IGNORE); is the canonical way to poke the progress engine in MPI. github.com/pmodels/armci-mpi/search?q=progress is how I implemented asynchronous progress threads in ARMCI-MPI. However, it's debatable whether this is worth the overhead of MPI_THREAD_MULTIPLE and consuming one hardware thread per process (or oversubscribing hardware threads). $\endgroup$ Sep 23, 2022 at 12:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.