-2

I am making a simple code in C++ using MPI to do parallel processing. I send a char message from process 4 to 5 and initialize the message with 'nothing' for all other processes.

So, I want to gather all messages for each process ('nothing' for all processes but the 5th which receives the char message that process 4 sent) and print them out for each process like

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
...
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
received
...

I tried several things like this for instance: https://stackoverflow.com/a/31932283/14901229, (you can see that in my code below) but it prints letter by letter...

Maybe someone could help me? Thanks in advance!

Here is my code:


int rank,nbproc, taille;
    char name[80];
    
    char message[] = "preceived";
    int longueur = strlen(message); 
    int len_buffer = 200;
    char Buffer_Hello[len_buffer];
    char receive[] = "nothing";    
    
 MPI_Init(&argc, &argv);

    MPI_Comm_size(MPI_COMM_WORLD, &nbproc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);  
    MPI_Get_processor_name(name, &taille);
    
    sprintf(Buffer_Hello,"Hello from process %d among %d of the machine %s",rank,nbproc,name);
    
    MPI_Send(Buffer_Hello,len_buffer,MPI_CHAR,0,rank+10,MPI_COMM_WORLD);

 if (rank == 4)
    {
        MPI_Send(&message[1],longueur+1,MPI_CHAR,5,2,MPI_COMM_WORLD);
 // sends the message from the second element
    }
 
    if (rank == 5)
    {   
        MPI_Recv(&receive,longueur+1,MPI_CHAR,4,2,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
    }

    int mylen = strlen(receive);
    int* recvcounts = new int[nbproc*sizeof(int)]; 

    
    MPI_Gather(&mylen,1,MPI_INT,recvcounts,1,MPI_INT,0,MPI_COMM_WORLD); 
    
    int totlen = 0; 
    int* displs = new int[nbproc*sizeof(int)];


    if(rank == 0)
    {
        displs[0] = 0;
        totlen += recvcounts[0] + 1; 

        for(int i=1; i < nbproc; i++)
        {
            totlen += recvcounts[i]+1; 
            displs[i] = displs[i-1] + recvcounts[i-1] + 1; 
        }
    }


    char* totalstring = new char[totlen*sizeof(char)]; 

    if(rank == 0)
    {
        for (int i=0; i<totlen; i++) 
            totalstring[i] = ' '; 
        
        totalstring[totlen] = '\0'; 
    }
  
       MPI_Gatherv(&receive, mylen, MPI_CHAR,
                totalstring, recvcounts, displs, MPI_CHAR,
                0, MPI_COMM_WORLD);

  
   if(rank == 0)
   {
       cout << Buffer_Hello << endl;
       
        for(int i = 1; i < nbproc; i++)
        {
            MPI_Recv(Buffer_Hello,len_buffer,MPI_CHAR,i,i+10,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            cout << Buffer_Hello << endl;
           cout << totalstring[i] << endl;
       
        }
   }

    MPI_Finalize(); 
    return 0;
}

My outputs:

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
o
Hello from process 2 among 8 of the machine jeremy-SATELLITE-P50-C
t
Hello from process 3 among 8 of the machine jeremy-SATELLITE-P50-C
h
Hello from process 4 among 8 of the machine jeremy-SATELLITE-P50-C
i
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
n
Hello from process 6 among 8 of the machine jeremy-SATELLITE-P50-C
g
Hello from process 7 among 8 of the machine jeremy-SATELLITE-P50-C
Dharman
  • 30,962
  • 25
  • 85
  • 135
Jejouze
  • 23
  • 6
  • I don't think it's the source of your problem, but you have rank 0 sending to itself and never receiving. In principle, MPI_Send could deadlock if it is implemented as synchronous send, but it is almost certainly buffered so it should be OK. – David Henty Aug 20 '21 at 11:09
  • 1
    please trim down your code to a [mcve] and clearly states both the expected result and the discrepancy between it and the current result. – Gilles Gouaillardet Aug 20 '21 at 11:13
  • Why are you testing for NaN and then not doing anything with that information? – Victor Eijkhout Aug 21 '21 at 15:56
  • @VictorEijkhout because I don't want to print the NaN, so if there is one, I print (and do) nothing, but if there is not, then it is the else part. I am aware that this is probably not the most optimized way... I am currently working on my problem with the gather and print of char, I am close, then I will likely publish my final code and maybe ask for suggestions of optimization. – Jejouze Aug 22 '21 at 10:55

1 Answers1

0

Here is a way I finally found to gather these char arrays and print them out for each process.

First, I take back all messages with different lengths from each process and make a big string with all the words and spaces between them. Probably not the better way but if someone has a better idea, please tell me!


 int mylen = strlen(receive); 
    int* recvcounts = new int[nbproc*sizeof(int)]; 

    
    MPI_Gather(&mylen,1,MPI_INT,recvcounts,1,MPI_INT,0,MPI_COMM_WORLD); 
    
    int totlen = 0; 
    int* space = new int[nbproc*sizeof(int)]; 


    if(rank == 0)
    {
        displs[0] = 0; 
        totlen += recvcounts[0] + 1; 
        for(int i=1; i < nbproc; i++)
        {
            totlen += recvcounts[i]+1; 
            space[i] = space[i-1] + recvcounts[i-1] + 1; 
        }
    }


    char* totalstring = new char[totlen*sizeof(char)]; 

    if(rank == 0)
    {
        for (int i=0; i<totlen; i++) 
            totalstring[i] = ' '; 
        
        totalstring[totlen] = '\0'; 
    }
  
  
       MPI_Gatherv(&receive, mylen, MPI_CHAR,
                totalstring, recvcounts, space, MPI_CHAR,
                0, MPI_COMM_WORLD);

Then I split the totalstring into pieces and I print them out with the correct order in the process 0.


    char* piece = strtok(totalstring," "); 
  
   if(rank == 0)
   {
       cout << Buffer_Hello << endl;
        cout << piece << endl;
        for(int i = 1; i < nbproc; i++)
        {
            MPI_Recv(Buffer_Hello,len_buffer,MPI_CHAR,i,i+10,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            cout << Buffer_Hello << endl;
           
            if(piece != NULL)  
            {
                piece = strtok(NULL," "); 
          
                cout << piece << endl;
            }
           
        }
   }

And here is the result:

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 2 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 3 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 4 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
received
Hello from process 6 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 7 among 8 of the machine jeremy-SATELLITE-P50-C
nothing

So, as you can see it works, but it is probably not the best way to do it, so if someone has a better idea, don't hesitate!

Jejouze
  • 23
  • 6