Using MPI_Reduce and MPI_Scatter in C with mpi - c

I'm new in mpi, from this code I want to distribute one row of 2D array to all processor for example
p1 = 1,2,3,4
p2 = 5,6,7,8
p3 = 9,10,11,12
p4 = 13,14,15,16
when run the program with (mpirun -np 4 ./a),
MPI_Scatter
works fine but
MPI_Reduce
cause stopping in terminal. I do not know how can I deal with MPI_Reduce by found localmax or ( mymax). Can any one help?
#include "mpi.h"
#include <stdio.h>
#define size 4
int main ()
{
int np, rank, sendcount, recvcount, source,i;
int recvbuf[size];
int mymax;
int max=0;
MPI_Init(NULL,NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &np);
int sendbuf[size][size] ={
{1, 2, 3, 4},
{5, 6, 7, 8},
{9,10,11, 12},
{13, 14, 15, 16}};
source = 1;
sendcount = size;
recvcount = size;
MPI_Scatter(sendbuf,sendcount,MPI_INT,recvbuf,recvcount,MPI_INT,source,MPI_COMM_WORLD);
printf("rank= %d Results: %d %d %d %d \n",rank,recvbuf[0],recvbuf[1],recvbuf[2],recvbuf[3]);
//Each processor has a row, now find local max
mymax = recvbuf[0];
for(i=0;i<recvcount;i++) {
if(mymax < recvbuf[i]) {
mymax = recvbuf[i];
}
}
MPI_Reduce(&mymax,&max ,1,MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (rank==0) {
printf(" Processor %d has max data after reduce : max= %d ", rank,max);
}
else
printf("----.\n");
MPI_Finalize();
}

Related

openmpi: printf not waiting for scanf

int main( int argc, char *argv[])
{
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int x;
printf("Rank: %d\n", rank);
fflush(stdout);
scanf("%d", &x);
MPI_Finalize();
return 0;
}
when i run it on 2+ tasks it prints everything, but scanf used once in the end
(base) curer:hw4 user$ mpic++ -o a ./-.cpp
(base) curer:hw4 user$ mpirun -oversubscribe -np 2 ./a
Rank: 0
Rank: 1
7
scanf in the end and i entered 7
I want to be like that
(base) curer:hw4 user$ mpic++ -o a ./-.cpp
(base) curer:hw4 user$ mpirun -oversubscribe -np 2 ./a
Rank: 0
8
Rank: 1
7
printf Rank i then scanf any number
If you really really want each MPI tasks to do a job one after another, in order, you could synchronize the jobs by a series of MPI_Send and MPI_Recv.
This a working example:
#include <stdio.h>
#include <mpi.h>
int read(int rank)
{
int x;
printf("Rank: %d\n", rank);
fflush(stdout);
scanf("%d", &x);
return x;
}
int main( int argc, char *argv[])
{
int rank, size, send, receive, x;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
send = 1;
if (rank == 0)
{
x = read(rank);
if (size > 1)
MPI_Send(&send, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
}
else
{
MPI_Recv(&receive, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
x = read(rank);
MPI_Send(&send, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
In the code above, each task send a message to the next one, and (except the root) wait a message from the previous task before doing the job.
However, as noted in the comments, it is much more common to let a task, typically the root, to do the input job and then distribute the inputs among the task, using MPI_Bcast or MPI_Scatter.

Storing values starting from a particular location in MPI_Recv

I am testing an example, where I am trying to send an array of 4 elements from process 0 to process 1 and I am doing so using MPI_Type_contiguous
This is the code for the same
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int main( int argc, char *argv[] )
{
MPI_Init(&argc, &argv);
int myrank, size; //size will take care of number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &myrank) ;
MPI_Comm_size(MPI_COMM_WORLD, &size);
//declaring the matrix
double mat[4]={1, 2, 3, 4};
int r=4;
double snd_buf[r];
double recv_buf[r];
double buf[r];
int position=0;
MPI_Status status[r];
MPI_Datatype type;
MPI_Type_contiguous( r, MPI_DOUBLE, &type );
MPI_Type_commit(&type);
//sending the data
if(myrank==0)
{
MPI_Send (&mat[0], r , type, 1 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
}
//receiving the data
if(myrank==1)
{
MPI_Recv(recv_buf, r, type, 0 /*src*/ , 100 /*tag*/, MPI_COMM_WORLD,&status[0]);
}
//printing
if(myrank==1)
{
for(int i=0;i<r;i++)
{
printf("%lf ",recv_buf[i]);
}
printf("\n");
}
MPI_Finalize();
return 0;
}
As one can see the recv_buf size is same as the size of the array. And the output that is being printed is 1 2 3 4
Now what I trying to do is that, say the recv_buf size is 10 and I want to store the elements starting from location 6 to 9. For which I have written this code, but to my surprise it is giving no output
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int main( int argc, char *argv[] )
{
MPI_Init(&argc, &argv);
int myrank, size; //size will take care of number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &myrank) ;
MPI_Comm_size(MPI_COMM_WORLD, &size);
//declaring the matrix
double mat[4]={1, 2, 3, 4};
int r=4;
double snd_buf[r];
double recv_buf[10]; //declared it of size 10
double buf[r];
int position=0;
MPI_Status status[r];
MPI_Datatype type;
MPI_Type_contiguous( r, MPI_DOUBLE, &type );
MPI_Type_commit(&type);
//packing and sending the data
if(myrank==0)
{
MPI_Send (&mat[0], r , type, 1 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
}
//receiving the data
if(myrank==1)
{
MPI_Recv(&recv_buf[6], r, type, 0 /*src*/ , 100 /*tag*/, MPI_COMM_WORLD,&status[0]);
}
//printing
if(myrank==1)
{
for(int i=6;i<10;i++)
{
printf("%lf ",recv_buf[i]);
}
printf("\n");
}
MPI_Finalize();
return 0;
}
Where am I going wrong?
From this SO Thread one can read:
MPI_Type_contiguous is for making a new datatype which is count copies
of the existing one. This is useful to simplify the processes of
sending a number of datatypes together as you don't need to keep track
of their combined size (count in MPI_send can be replaced by 1).
That being said, in your MPI_Send call:
MPI_Send (&mat[0], r , type, 1 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
you should not send an array with 'r' elements of type 'type', but rather send 1 element of type 'type' (which is equal to 4 doubles). One of the goals of the MPI_Type_contiguous is to abstract away the count to 1 instead of keeping track of the number of elements.
The same applies to your recv call:
MPI_Recv(&recv_buf[6], 1, type, 0 /*src*/ , 100 /*tag*/, MPI_COMM_WORLD,&status[0]);
Finally, you should also free the custom type accordingly:
MPI_Type_free(&type);
The entire code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int main( int argc, char *argv[] )
{
MPI_Init(&argc, &argv);
int myrank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank) ;
MPI_Comm_size(MPI_COMM_WORLD, &size);
double mat[4]={1, 2, 3, 4};
int r=4;
double snd_buf[r];
double recv_buf[10];
MPI_Status status;
MPI_Datatype type;
MPI_Type_contiguous( r, MPI_DOUBLE, &type );
MPI_Type_commit(&type);
if(myrank==0)
MPI_Send (&mat[0], 1 , type, 1, 100, MPI_COMM_WORLD);
else if(myrank==1)
{
MPI_Recv(&recv_buf[6], 1, type, 0, 100, MPI_COMM_WORLD, &status);
for(int i=6;i<10;i++)
printf("%lf ",recv_buf[i]);
printf("\n");
}
MPI_Type_free(&type);
MPI_Finalize();
return 0;
}
The Output:
1.000000 2.000000 3.000000 4.000000

How to use multi-denominational array in MPI_Gather

I have written the following simple program in C to learn about how to send 2D arrays using MPI_Gather. As shown in line 24 and 49 of the code, MPI_Gather is used incorrectly. Following is the result I should get:
Final array result:
array[0][0]:2, array[0][1]:2, array[0][2]:2,
array[1][0]:2, array[1][1]:2, array[1][2]:2,
array[2][0]:3, array[2][1]:3, array[2][2]:3,
array[3][0]:3, array[3][1]:3, array[3][2]:3,
array[4][0]:4, array[4][1]:4, array[4][2]:4,
array[5][0]:4, array[5][1]:4, array[5][2]:4,
array[6][0]:5, array[6][1]:5, array[6][2]:5,
array[7][0]:5, array[7][1]:5, array[7][2]:5,
Since I am using MPI_Gather incorrectly, when I run this program, some of the array elements doesn't show the correct result. I am using 4 processors to run this program. Please show me how to use MPI_Gather with a 2D array, with an example if possible
To Compile:$ mpicc test.c -o test
To Run:$ mpirun -np 4 test
#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 i, j, total;
int localdata[2][2];
int final_arr[8][3];
if (world_rank == 0)
{
printf("\n* At Process %d \n", world_rank);
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
localdata[i][j]=world_rank+2;
}
} /*Error: wants to send the full 2 by 3 localdata array to root*/
MPI_Gather(localdata, 6, MPI_INT, final_arr, 6, MPI_INT,0, MPI_COMM_WORLD);
if (world_rank == 0)
{
printf("\n\nFinal array result:\n");
for(i=0;i<8;i++)
{
for(j=0;j<3;j++)
{
printf("array[%d][%d]:%d, ",i,j,final_arr[i][j]);
}
printf("\n");
}
}
}
else
{
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
localdata[i][j]=world_rank+2;
}
} /*Error: wants to send the full 2 by 3 localdata array to root*/
MPI_Gather(localdata, 6, MPI_INT, final_arr, 6, MPI_INT,0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}

Communication between two processors (Parallel Programming)

I want to write a code that:
P0 processor gets an array from keyboard, and sends that array to P1 processor.
P1 processor prints all of the values to screen. For example:
[P0]: Enter the size of array: 1
[P0]: Enter the elements of array: 3
[P1]: The array is: 3
[P0]: Enter the size of array: 3
[P0]: Enter the elements of array: 5 7 5
[P1]: The array is: 5 7 5
.
.
.
and here is my first work. Too many faults I think. But I'm new. Want to learn how to code.
#include <stdio.h>
#include <mpi.h>
#define n 100
int main(int argc, char *argv[]){
int my_rank, size_cm;
int value, i;
int dizi[n];
double senddata[n];
double recvdata[n];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size_cm);
value=0;
if(my_rank == 0){
printf("[%d]: Enter the size of array: ",&my_rank);
scanf("%d",value);
printf("[%d]: Enter the elements of array",&my_rank);
for(i=0; i<n; i++){
scanf("%d", &dizi[n]);
senddata[0] = dizi[];
MPI_Send(senddata, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
}
}
if(my_rank == 1){
MPI_Recv(recvdata, 1, MPI_INT, 0, 0, MPI_COMM_WORLD,
printf("[%d]: The array is: %d ",&my_rank, dizi[n]);
}
MPI_Finalize();
return 0;
}
To get a minimal example that compile, I added the missing argument to MPI_Recv():
MPI_Status status;
MPI_Recv(recvdata, 1, MPI_INT, 0, 0, MPI_COMM_WORLD,&status);
I also modifed senddata[0] = dizi[]; to senddata[0] = dizi[i];
As I tried to compile the code you provided, I got a warning :
format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *
The function scanf() needs the pointer to the data to modify it, so int a;scanf("%d",&a); is correct. But printf() just needs the data since it will not modify it : int a;printf("%d",a); is the right way to go.
If you want the array to be populated, use scanf("%d", &dizi[i]);, not scanf("%d", &dizi[n]);. n is the lenght of array dizi. Hence, the index n is out of the array, since indexes of arrays start at 0. This could trigger undefined behaviors (strange values, segmentation fault or even a correct result !).
Since MPI_Send() is called in the for(i=0; i<n; i++), process 0 tries to send n messages to process 1. But process 1 only receives one. Hence, process 0 will be locked at i=1, waiting for process 1 to receive the second message. This is a deadlock.
I assume you are trying to send an array from process 0 to process 1. The following code based on your should do the trick. The actual length of the array is n_arr:
#include <stdio.h>
#include <mpi.h>
#include <stdlib.h>
#define n 100
int main(int argc, char *argv[]){
int my_rank, size_cm;
int n_arr;
int i;
int dizi[n];
// double senddata[n];
// double recvdata[n];
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size_cm);
if(my_rank == 0){
// fflush(stdout); because the standard output is buffered...
printf("[%d]: Enter the size of array: ",my_rank);fflush(stdout);
if(scanf("%d",&n_arr)!=1){fprintf(stderr,"input error\n");exit(1);}
if(n_arr>100){
fprintf(stderr,"The size of the array is too large\n");exit(1);
}
printf("[%d]: Enter the elements of array",my_rank);fflush(stdout);
for(i=0; i<n_arr; i++){
if(scanf("%d", &dizi[i])!=1){fprintf(stderr,"input error\n");exit(1);}
}
//sending the length of the array
MPI_Send(&n_arr, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
//senfing the array
MPI_Send(dizi, n_arr, MPI_INT, 1, 0, MPI_COMM_WORLD);
}
if(my_rank == 1){
// receiving the length of the array
MPI_Recv(&n_arr, 1, MPI_INT, 0, 0, MPI_COMM_WORLD,&status);
//receiving the array
MPI_Recv(dizi, n_arr, MPI_INT, 0, 0, MPI_COMM_WORLD,&status);
printf("[%d]: The array of size %d is: ",my_rank,n_arr);
for(i=0; i<n_arr; i++){
printf("%d ",dizi[i]);
}
printf("\n");
}
MPI_Finalize();
return 0;
}
It is compiled by running mpicc main.c -o main and ran by mpirun -np 2 main
I added some stuff to check if the input is correct (always a good thing) and to handle the case of n_arr being larger than n=100. The last one could be avoided by using malloc() to allocate memory for the array: this part is left to you !

MPI derived datatype works for floats, but not for doubles. Is it an alignment issue?

I have a weird issue related to a C-structure that is communicated with the help of an MPI derived datatype. The example below works; it simply sends a message consisting of one integer plus 4 float values.
Minmum working example:
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int i, rank, tag = 1;
MPI_Status status;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Array of doubles plus element count
typedef struct {
int row;
float elements[4];
} My_array;
// Derived datatype for an array of doubles plus element count
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_FLOAT};
MPI_Aint extent, lb;
MPI_Type_get_extent(MPI_INT, &lb, &extent);
MPI_Aint displacements[2] = {0, extent};
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
if(rank == 0) {
My_array array1 = {3, 3.1, 3.2, 3.3, 3.4};
MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD);
}
if(rank == 1) {
My_array array2;
MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status);
printf("Rank %d received elements of row %d:\n", rank, array2.row);
for(i = 0; i < 4; i++)
printf("\t%.1f\n", array2.elements[i]);
}
MPI_Type_free(&MY_ARRAY_TYPE);
MPI_Finalize();
}
If you have access to an MPI installation, the example can be compiled by mpicc -o example example.c and run by mpirun -np 2 example.
The output should be
Rank 1 received elements of row 3:
3.1
3.2
3.3
3.4
The problem:
Now when the array of floats is changed to an array of doubles, and accordingly MPI_FLOATto MPI_DOUBLE, I get a wrong result.
This code:
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int i, rank, tag = 1;
MPI_Status status;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Array of doubles plus element count
typedef struct {
int row;
double elements[4];
} My_array;
// Derived datatype for an array of doubles plus element count
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint extent, lb;
MPI_Type_get_extent(MPI_INT, &lb, &extent);
MPI_Aint displacements[2] = {0, extent};
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
if(rank == 0) {
My_array array1 = {3, 3.1, 3.2, 3.3, 3.4};
MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD);
}
if(rank == 1) {
My_array array2;
MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status);
printf("Rank %d received elements of row %d:\n", rank, array2.row);
for(i = 0; i < 4; i++)
printf("\t%.1f\n", array2.elements[i]);
}
MPI_Type_free(&MY_ARRAY_TYPE);
MPI_Finalize();
}
produces:
Rank 1 received elements of row 3:
3.1
3.2
3.3
0.0
I tried around a bit, using other data in the struct and the derived datatype (e.g., an array of integers instead of just one, int/MPI_INT instead of float/MPI_FLOAT, etc.) and saw that the problem arises only when doubles are used. Which makes me suspect that this might be an alignment issue of sorts - but I am stuck there. MPI should take care of alignments automatically.
Question: Why does the above example work with float/MPI_FLOAT, but not with double/MPI_DOUBLE and how can I fix it?
Some machine specifics that might be relevant:
CPU: AMD Opteron 6134
Address sizes: 48 bit
Alignment: 64
Compiler: gcc 4.4.7
MPI library: (Unfortunately) Vendor specific
Edit: as suggested in the comments by Vladimir F, I added the code that does not work.
I just found out what the problem is: it is indeed alignment. That the second code listing produces the first 3 doubles correctly is nothing but a weird coincidence...By using the extend of MPI_INT as the offset of the following value, I assumed that there would be no padding. It is better to compute the offsets like this:
#include <stddef.c>
...
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint displacements[2];
displacements[0] = offsetof(My_array, row);
displacements[1] = offsetof(My_array, elements);
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
...
I'd really be interested to see how it can work out this way...why do we get 3 correct values and one 0.0? Since the alignment was off by 4 bytes and doubles are represented by 8 bytes on my platform, why didn't I get some random numbers? How can the first 3 have been decoded correctly if they each took the lower 4 bytes of one double plus the upper 4 of the next double?

Resources