Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Send/Receive in MPI using all processors

This program written using C Lagrange and MPI. I am new to MPI and want to use all processors to do some calculations, including process 0. To learn this concept, I have written the following simple program. But this program hangs at the bottom after receiving input from the process 0 and won't send results back to the process 0.

#include <mpi.h>
#include <stdio.h>

int main(int argc, char** argv) {    
    MPI_Init(&argc, &argv);
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    int number;
    int result;
    if (world_rank == 0) 
    {
        number = -2;
        int i;
        for(i = 0; i < 4; i++)
        {
            MPI_Send(&number, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
        }
        for(i = 0; i < 4; i++)
        {           /*Error: can't get result send by other processos bellow*/
            MPI_Recv(&number, 1, MPI_INT, i, 99, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            printf("Process 0 received number %d from i:%d\n", number, i);
        }
    } 
    /*I want to do this without using an else statement here, so that I can use process 0 to do some calculations as well*/

    MPI_Recv(&number, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
    printf("*Process %d received number %d from process 0\n",world_rank, number);
    result = world_rank + 1;
    MPI_Send(&result, 1, MPI_INT, 0, 99, MPI_COMM_WORLD);  /* problem happens here when trying to send result back to process 0*/

    MPI_Finalize();
}

Runing and getting results:

:$ mpicc test.c -o test
:$ mpirun -np 4 test

*Process 1 received number -2 from process 0
*Process 2 received number -2 from process 0
*Process 3 received number -2 from process 0
/* hangs here and will not continue */

If you can, please show me with an example or edit the above code if possible.

like image 963
D P. Avatar asked Oct 10 '16 22:10

D P.


2 Answers

I don't really get what would be wrong with using 2 if statements, surrounding the working domain. But anyway, here is an example of what could be done.

I modified your code to use collective communications as they make much more sense than the series of send/receive you used. Since the initial communications are with a uniform value, I use a MPI_Bcast() which does the same in one single call.
Conversely, since the result values are all different, a call to MPI_Gather() is perfectly appropriate.
I also introduce a call to sleep() just to simulate that the processes are working for a while, prior to sending back their results.

The code now looks like this:

#include <mpi.h>
#include <stdlib.h>   // for malloc and free
#include <stdio.h>    // for printf
#include <unistd.h>   // for sleep

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

    MPI_Init( &argc, &argv );
    int world_rank;
    MPI_Comm_rank( MPI_COMM_WORLD, &world_rank );
    int world_size;
    MPI_Comm_size( MPI_COMM_WORLD, &world_size );

    // sending the same number to all processes via broadcast from process 0
    int number = world_rank == 0 ? -2 : 0;
    MPI_Bcast( &number, 1, MPI_INT, 0, MPI_COMM_WORLD );
    printf( "Process %d received %d from process 0\n", world_rank, number );

    // Do something usefull here
    sleep( 1 );
    int my_result = world_rank + 1;

    // Now collecting individual results on process 0
    int *results = world_rank == 0 ? malloc( world_size * sizeof( int ) ) : NULL;
    MPI_Gather( &my_result, 1, MPI_INT, results, 1, MPI_INT, 0, MPI_COMM_WORLD );

    // Process 0 prints what it collected
    if ( world_rank == 0 ) {
        for ( int i = 0; i < world_size; i++ ) {
            printf( "Process 0 received result %d from process %d\n", results[i], i );
        }
        free( results );
    }

    MPI_Finalize();

    return 0;
}

After compiling it as follows:

$ mpicc -std=c99 simple_mpi.c -o simple_mpi

It runs and gives this:

$ mpiexec -n 4 ./simple_mpi
Process 0 received -2 from process 0
Process 1 received -2 from process 0
Process 3 received -2 from process 0
Process 2 received -2 from process 0
Process 0 received result 1 from process 0
Process 0 received result 2 from process 1
Process 0 received result 3 from process 2
Process 0 received result 4 from process 3
like image 72
Gilles Avatar answered Oct 05 '22 17:10

Gilles


Actually, processes 1-3 are indeed sending the result back to processor 0. However, processor 0 is stuck in the first iteration of this loop:

for(i=0; i<4; i++)
{      
    MPI_Recv(&number, 1, MPI_INT, i, 99, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    printf("Process 0 received number %d from i:%d\n", number, i);
}

In the first MPI_Recv call, processor 0 will block waiting to receive a message from itself with tag 99, a message that 0 did not send yet.

Generally, it is a bad idea for a processor to send/receive messages to itself, especially using blocking calls. 0 already have the value in memory. It does not need to send it to itself.

However, a workaround is to start the receive loop from i=1

for(i=1; i<4; i++)
{           
    MPI_Recv(&number, 1, MPI_INT, i, 99, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    printf("Process 0 received number %d from i:%d\n", number, i);
}

Running the code now will give you:

Process 1 received number -2 from process 0
Process 2 received number -2 from process 0
Process 3 received number -2 from process 0
Process 0 received number 2 from i:1
Process 0 received number 3 from i:2
Process 0 received number 4 from i:3
Process 0 received number -2 from process 0

Note that using MPI_Bcast and MPI_Gather as mentioned by Gilles is a much more efficient and standard way for data distribution/collection.

like image 25
jahed Avatar answered Oct 05 '22 15:10

jahed