How to use multi-denominational array in MPI_Gather - c

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;
}

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

Using MPI_Reduce and MPI_Scatter in C with mpi

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();
}

MPI Segmentationi fault MPI_Scatter using C

I am new in this area and use OpenMPI and C. I try to find out why my code leads to an Segmentatioin fault. I red already a lot about MPI but I did not find any help. It took me already hours. So I decided to ask here for help.
I get the expected result of my code. But I also get every time an error message.
Is it right how I use MPI_Scatter in my case?
Here is my simple code:
#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
const int MASTER_RANK = 0;
#define DIM 3
int main(int argc, char* argv[])
{
int numProc, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numProc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int n = 9;
double *m;
double *m_client;
m_client = (double *)malloc(3);
if(rank == MASTER_RANK)
{
m = (double* )malloc(n);
for(int i=0; i<n; i++)
{
m[i] = (double)i+1.0;
}
}
MPI_Scatter(m, 3, MPI_DOUBLE, m_client, 3, MPI_DOUBLE, MASTER_RANK, MPI_COMM_WORLD);
printf("Process %d:\n", rank);
for(int i=0; i < 3; i++)
{
printf(" (%lf", m_client[i]);
m_client[i] += 1000*rank;
printf(" -> %lf)", m_client[i]);
printf("\n");
}
printf( "\n" );
MPI_Gather(m_client, 3, MPI_DOUBLE, m, 3, MPI_DOUBLE, MASTER_RANK, MPI_COMM_WORLD);
if(rank == MASTER_RANK)
{
printf("Master: Received= \n");
for(int i=0; i<numProc; i++)
{
for(int j=0; j < 3; j++)
{
int idx = i*3 + j;
printf("%lf ", m[idx]);
}
printf("from Process %d\n", i);
}
}
free(m);
free(m_client);
MPI_Finalize();
exit(0);
}
I build my MPI file by using mpicc mpifile.c -o mpifile and run it with mpirun -np 3 ./mpifile. I use 3 processes.
The error I get is:
[Samuel-Z97-HD3:14361] *** Process received signal ***
[Samuel-Z97-HD3:14361] Signal: Segmentation fault (11)
[Samuel-Z97-HD3:14361] Signal code: (128)
[Samuel-Z97-HD3:14361] Failing at address: (nil)
I am using Ubuntu and vim / Geany.
Your code has two problems.
Both your malloc() calls are having wrong sizes. You should allocate number of bytes instead of number of doubles. E.g. instead of calling malloc(3), call malloc(3*sizeof(double)).
Another problem is that your variable m should be initialized to NULL. Alternatively, you could surround free(m) with if(rank == MASTER_RANK). As is, a non-master process calls free(m) where m is uninitialized and could contain arbitrary value.

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 !

Resources