MPI_Gather send and recieving array error - c

#include<mpi.h>
#include<stdio.h>
int main(int argc,char * argv[])
{
int rank,size,m;
int arr[1000];
int b[100];
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
if(rank == 0)
{
scanf("%d",&m);
for(int i=0;i<size*m;i++)
{
scanf("%d",&arr[i]);
}
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Scatter(arr,m,MPI_INT,b,m,MPI_INT,0,MPI_COMM_WORLD);
printf("in process %d \n",rank);
for(int i=0;i<m;i++)
{
printf("%d ",b[i]);
}
printf("\n");
MPI_Finalize();
return 0;
}
Input
mpiexec -n 4 ./three
Actual Output
in process 2
in process 1
in process 3
2
1 2 3 4 5 6 7 8
in process 0
1 2
Expected Output
2
1 2 3 4 5 6 7 8
in process 0
1 2
in process 1
3 4
in process 2
5 6
in process 3
7 8

You have not broadcast the value of m so only rank 0 has a correct value - it looks like it is defaulting to m=0 on other ranks, hence their lack of output.
The barrier is not required - MPI collectives do all the necessary synchronisation automatically.
If you replace your barrier call with:
MPI_Bcast(&m, 1, MPI_INT, 0, MPI_COMM_WORLD);
then your code works as expected (subject to the output not being as clean as you might expect as pointed out by Gilles above).

Related

C, MPI: Program not terminating and not printing numbers

#include "mpi.h"
#include <stdio.h>
int main(int argc,char *argv[]){
int numtasks, rank, rc, count, tag=1, i =0;
MPI_Status Stat;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) //for process 0 we print received messages
{
for(i=0; i< 9; i ++){
printf("value of i is: %d\n",i );
rc = MPI_Recv(&inmsg, 1, MPI_CHAR, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &Stat);
printf("Task %d: Received %d char(s) from task %d with tag %d \n", rank, count, Stat.MPI_SOURCE, Stat.MPI_TAG);
}
}
else //for the other 9 processes
{
if(rank % 2 == 0){ //if rank is an even number
rc = MPI_Send(&outmsg, 1, MPI_CHAR, 0, tag, MPI_COMM_WORLD); //send message to process with rank 0
}
}
MPI_Finalize();
}
//
This program is run with 10 processes. Process with rank 0 receives messages and prints them out if the source process has an even numbered rank. Processes with rank other than 0 send process with rank 0 a message containing a character 'x'
Now, in regards to rank 0, it has a for loop that basically loops 9 times. In the loop it prints out the value of the iterating variable i, and the received character and source process.
However, when I run my program it does not terminate.
The output looks like this:
Task 0: Received 0 char(s) from task 2 with tag 1
value of i is: 1
Task 0: Received 0 char(s) from task 6 with tag 1
value of i is: 2
Task 0: Received 0 char(s) from task 4 with tag 1
value of i is: 3
Task 0: Received 0 char(s) from task 8 with tag 1
value of i is: 4
How do I get it to print the other values of i such as 5,6,7,8,9?
You're using a master-slave architecture for parallel processing, your process 0 is the master and is waiting for the input of 9 other process, but in your code only process with even id number will fire an output, namely process 2, 4, 6, 8.
you didn't put behavior for process 1,3,5,7 and 9 so the master is still waiting for them hence, the program waiting for parallel process to finish:
you need to complete your source code here
if(rank % 2 == 0){ //if rank is an even number
rc = MPI_Send(&outmsg, 1, MPI_CHAR, 0, tag, MPI_COMM_WORLD); //send message to process with rank 0
}else{
//logic for process 1,3,5,7,9
}

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.
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
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.

Trouble receiving a subset of an array using MPI Datatypes

I'm having trouble sending and receiving columns of a 2-d array.
I have 2 processes. The first process has a 2-d array and I want to send parts of it to the second process. So say each rank has a 9x9 array, I'd like rank 0 to send to rank 1 just certain columns:
Example:
-1--2--3-
-2--3--4-
-5--6--7-
...
I want to send "1,2,5,..." and "3,4,7,...".
I've written code to just send the first column, and I've read through this answer and I believe I've correctly defined an MPI_Type_vector for the column:
MPI_Type_vector(dime,1,dime-1,MPI_INT,&LEFT_SIDE);
Where dime here, 9, is the size of the array; I'm sending 9 blocks of 1 MPI_INT, each separated by a stride of 8 - but even just sending this one column is giving me invalid results.
My code follows:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define dime 9
int main (int argc, char *argv[])
{
int size,rank;
const int ltag=2;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Get the rank of the process
int table[dime][dime];
for (int i=0; i<dime; i++)
for (int j=0; j<dime; j++)
table[i][j] = rank;
int message[dime];
MPI_Datatype LEFT_SIDE;
MPI_Type_vector(dime,1,dime-1,MPI_INT,&LEFT_SIDE);
MPI_Type_commit(&LEFT_SIDE);
if(rank==0) {
MPI_Send(table, 1, LEFT_SIDE, 1, ltag, MPI_COMM_WORLD);
} else if(rank==1){
MPI_Status status;
MPI_Recv(message, 1, LEFT_SIDE, 0, ltag, MPI_COMM_WORLD, &status);
}
if(rank == 1 ){
printf("Rank 1's received data: ");
for(int i=0;i<dime;i++)
printf("%6d ",*(message+i));
printf("\n");
}
MPI_Finalize();
return 0;
}
But when I run it and look at the data I'm receiving, I get either all zeros or gibberish:
$ mpicc -o datatype datatype.c -Wall -g -O3 -std=c99
$ mpirun -np 2 datatype
Rank 1's received data: 0 32710 64550200 0 1828366128 32765 11780096 0 0
Where the numbers change each time. What am I doing wrong?
#Mort's answer is correct and was first; I just want to expand on it with some ASCII-art diagrams to try to drive home his messages.
An MPI Datatype describes how data is laid out in memory. Let's take a look at your 2d array for a smaller dime (say 4) and the corresponding MPI_Type_vector:
MPI_Type_vector(count=dime, blocksize=1, stride=dime-1, type=MPI_INT ...
= 4 =1 = 3
data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
Vector: X - - X - - X - - X - -
Note that the stride in MPI Types are the distances between the starts of the types, not the gap size between them; so you actually want stride=dime here, not dime-1. That's easily fixed, but isn't the actual problem:
MPI_Type_vector(count=dime, blocksize=1, stride=dime, type=MPI_INT ...
= 4 =1 = 4
data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
Vector: X - - - X - - - X - - - X - - -
Ok, so far so good, we're selecting out the correct elements. But we're not receiving them properly; the code trying to receive the data into an array of size dime, using the same layout:
int message[dime];
MPI_Recv(message, 1, LEFT_SIDE, 0, ...
message = { 0, 1, 2, 3 };
Vector: X - - - X - - - X - - - X - - -
The vector goes well outside the range of message, which (a) leaves uninitialized data in message, which is the source of the gibberish, and (b) possibly causes segmentation errors for going outside the bounds of the array.
Crucially, one of these MPI_Type_vectors describes the layout of the desired data in the 2d matrix, but does not describe the layout of the same data as it's received into a compact 1d array.
There are two choices here. Either receive the data into the message array simply as dime x MPI_INT:
// ....
} else if(rank==1){
MPI_Status status;
MPI_Recv(message, dime, MPI_INT, 0, ltag, MPI_COMM_WORLD, &status);
}
//...
$ mpirun -np 2 datatype
Rank 1's received data: 0 0 0 0 0 0 0 0 0
Or directly receive the data right into the 2d matrix on Rank 1, overwriting the appropriate columns:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define dime 9
int main (int argc, char *argv[])
{
int size,rank;
const int ltag=2;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Get the rank of the process
int table[dime][dime];
for (int i=0; i<dime; i++)
for (int j=0; j<dime; j++)
table[i][j] = rank;
MPI_Datatype LEFT_SIDE;
MPI_Type_vector(dime,1,dime,MPI_INT,&LEFT_SIDE);
MPI_Type_commit(&LEFT_SIDE);
if(rank==0) {
MPI_Send(table, 1, LEFT_SIDE, 1, ltag, MPI_COMM_WORLD);
} else if(rank==1){
MPI_Status status;
MPI_Recv(table, 1, LEFT_SIDE, 0, ltag, MPI_COMM_WORLD, &status);
}
if(rank == 1 ){
printf("Rank 1's new array:\n");
for(int i=0;i<dime;i++) {
for(int j=0;j<dime;j++)
printf("%6d ",table[i][j]);
printf("\n");
}
printf("\n");
}
MPI_Type_free(&LEFT_SIDE);
MPI_Finalize();
return 0;
}
Running gives
$ mpicc -o datatype datatype.c -Wall -g -O3 -std=c99
$ mpirun -np 2 datatype
Rank 1's new array:
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
(after correcting the MPI_Type_vector)
The remaining bit about how to extend this to multiple columns is probably best left to another question.
I'm not quite sure what exactly your problem is (please make this clear in your questions, you'll get much better answers! See also How do I ask good questions.), but your code has several issues.
You need to useMPI_Type_vector(dime,1,dime,MPI_INT,&LEFT_SIDE);, since you are sending every dime-th element of the matrix. In C, a 2-d array is simply stored as a standard array, with element [i][j] being stored at index [i*dime+j]. You want to send the elements at indices 0, dime, 2*dime, 3*dime,...
If you use your LEFT_SIDE datatype to receive the data, MPI will store your data items with a gap of dime elements - analogously to the sender. However, your receive buffer message is a simple array. You need to receive the data like this: MPI_Recv(message, dime, MPI_INT, 0, LTAG, newcomm,&status);. This operation will receive dime integers and put them into your message array.
Edit: I updated my answer to match the significantly changed question.

MPI C Tree Structured Global Sum

How do I pair processes using MPI in C? It's a tree structured approach. Process 0 should be adding from all of the other even processes, which they are paired with. I only need it to work for powers of 2.
Should I be using MPI_Reduce instead of MPI Send/Receive? If so, why?
My program doesn't seem to get past for loop inside the first if statement. Why?
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <mpi.h>
int main(void){
int sum, comm_sz, my_rank, i, next, value;
int divisor = 2;
int core_difference = 1;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
srandom((unsigned)time(NULL) + my_rank);
value = random() % 10;
//process should recieve and add
if (my_rank % divisor == 0){
printf("IF----");
printf("Process %d generates: %d\n", my_rank, value);
for (i = 0; i < comm_sz; i++)
{
MPI_Recv(&value, 1, MPI_INT, i, my_rank , MPI_COMM_WORLD, MPI_STATUS_IGNORE);
sum += value;
printf("Current Sum=: %d\n", sum);
}
printf("The NEW divisor is:%d\n", divisor);
divisor *= 2;
core_difference *= 2;
}
//sending the random value - no calculation
else if (my_rank % divisor == core_difference){
printf("ELSE----");
printf("Process %d generates: %d\n", my_rank, value);
MPI_Send(&value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
else
if (my_rank==0)
printf("Sum=: %d\n", sum);
MPI_Finalize();
return 0;
}
The problem is that your processes are all receiving from themselves. If I add a print statement before each send and receive with the processes involved in the operation, here's the output:
$ mpiexec -n 8 ./a.out
IF----Process 0 generates: 5
ELSE----Process 1 generates: 1
ELSE----Process 3 generates: 1
IF----Process 4 generates: 9
ELSE----Process 5 generates: 7
IF----Process 6 generates: 2
ELSE----Process 7 generates: 0
0 RECV FROM 0
1 SEND TO 0
3 SEND TO 0
4 RECV FROM 0
5 SEND TO 0
6 RECV FROM 0
7 SEND TO 0
IF----Process 2 generates: 7
2 RECV FROM 0
1 SEND TO 0 DONE
3 SEND TO 0 DONE
5 SEND TO 0 DONE
7 SEND TO 0 DONE
Obviously, everyone is hanging while waiting for rank 0, including rank 0. If you want to send to yourself, you'll need to use either MPI_Sendrecv to do both the send and receive at the same time or use nonblocking sends and receives (MPI_Isend/MPI_Irecv).
As you said, another option would be to use collectives, but if you do that, you'll need to create new subcommunicators. Collectives require all processes in the communicator to participate. You can't pick just a subset.

MPI Irecv cannot receive correctly to the first element of a buffer?

I've just been experimenting with MPI, and copied and ran this code, taken from the second code example at [the LLNL MPI tutorial][1].
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char ** argv) {
int num_tasks, rank, next, prev, buf[2], tag1 = 1, tag2 = 2;
MPI_Request reqs[4];
MPI_Status status[2];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_tasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
prev = rank - 1;
next = rank + 1;
if (rank == 0) prev = num_tasks - 1;
if (rank == (num_tasks - 1)) next = 0;
MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD,
&reqs[0]);
MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD,
&reqs[1]);
MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs[2]);
MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD, &reqs[3]);
MPI_Waitall(4, reqs, status);
printf("Task %d received %d from %d and %d from %d\n",
rank, buf[0], prev, buf[1], next);
MPI_Finalize();
return EXIT_SUCCESS;
}
I would have expected an output like this (for, say, 4 tasks):
$ mpiexec -n 4 ./m3
Task 0 received 3 from 3 and 1 from 1
Task 1 received 0 from 0 and 2 from 2
Task 2 received 1 from 1 and 3 from 3
Task 3 received 2 from 2 and 0 from 0
However, instead, I get this:
$ mpiexec -n 4 ./m3
Task 0 received 0 from 3 and 1 from 1
Task 1 received 0 from 0 and 2 from 2
Task 3 received 0 from 2 and 0 from 0
Task 2 received 0 from 1 and 3 from 3
That is, the message (with tag == 1) going into buffer buf[0] always gets value 0. Moreover, if I alter the code so that I declare the buffer as buf[3] rather than buf[2], and replace each instance of buf[0] with buf[2], then I get precisely the output I would have expected (i.e., the first output set given above). This looks as if, for some reason, something is overwriting the value in buf[0] with 0. But I can't see what that might be. BTW, as far as I can tell, my code (without the modification) exactly matches the code inthe tutorial, except for my printf.
Thanks!
Array of statuses must be of size 4 not 2. In your case MPI_Waitall corrupts memory when writing statuses.

Resources