Communication between two processors (Parallel Programming) - c

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 !

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

MPI_Scatter is receiving wrong values

My goal is to take an array of 6 integers and split them among 3 processes. However, the numbers in receiveBuffer are not correct. I don't know why the three processes don't contain integers from the original array.
#include<stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include "mpi.h"
#define ARRAY_SIZE 6
// simple print array method
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main (int argc, char *argv[])
{
srand(time(NULL));
int array[ARRAY_SIZE];
int rank, numNodes;
// fill array with random numbers and print
for(int i = 0; i < ARRAY_SIZE; i++)
array[i] = rand();
printArray(array, ARRAY_SIZE);
MPI_Init( &argc, &argv );
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size (MPI_COMM_WORLD,&numNodes);
int receiveBuffer[ARRAY_SIZE/numNodes];
if(rank == 0)
{
MPI_Scatter(array, ARRAY_SIZE/numNodes, MPI_INT, &receiveBuffer, 0, MPI_INT, rank, MPI_COMM_WORLD);
}
printf("ID: %d with %d items.\n", rank, ARRAY_SIZE/numNodes);
printArray(receiveBuffer, ARRAY_SIZE/numNodes);
MPI_Finalize();
return 0;
}
Additionally, why is the original array printing for each process? Doesn't parallelization begin after INIT?
There are two issues with your usage of MPI_Scatter()
MPI_Scatter() is a collective operation, and has hence to be invoked by all the ranks of the communicator (e.g. not only rank zero)
since you use MPI_INT for both send and receive datatype, the send and receive counts should be equal (e.g. use ARRAY_SIZE/numNodes instead of 0)
The MPI standard does not specify what happens before MPI_Init(), and it is very common that mpirun spawns all the tasks, so they all execute the code before MPI_Init(). That's why MPI_Init() is generally invoked at the very beginning of a MPI program.

Efficient usage of MPI_Allreduce

I have on every processor a list range with numbers. I want to determine the maximum number of every row of these lists range.
The first four lists range for every processor P0-P3. The red list contains the maximum values of each row which every processor after MPI_Allreduce gets.
Here is a working version of my code:
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <mpi.h>
//#define KEY_MAX 100
typedef struct{
int myrank;
int numprocs;
int *range;
} SubDomainKeyTree;
void compRange(SubDomainKeyTree *s, int myrank, int numprocs){
s->myrank = myrank;
s->numprocs = numprocs;
// Allocate memory for (numprocs+1) ranges
s->range = malloc((numprocs+1) * sizeof(int));
// Compute range values
for(int p=0; p<=numprocs; p++){
s->range[p] = rand()%100;
}
for(int p=0; p<s->numprocs; p++){
if(s->myrank == p){
for(int k=0; k<=s->numprocs; k++){
printf("Processor %d: %d random number is %d\n", p, k, s->range[k]);
}
printf("\n");
}
}
}
void compDynRange(SubD *s){
int rangeForAll[s->numprocs+1];
//////////////////////////////////
// This is not really efficient //
//////////////////////////////////
for(int r=0; r<=s->numprocs; r++){
MPI_Allreduce(&s->range[r], &rangeForAll[r], 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
}
for(int p=0; p<s->numprocs; p++){
if(s->myrank == p){
for(int k=0; k<=s->numprocs; k++){
s->range[k] = rangeForAll[k];
printf("Processor %d: %d random number after MPI_Allreduce is %d\n", p, k, s->range[k]);
}
printf("\n");
}
}
}
int main(int argc, char **argv){
int nameLen;
char processorName[MPI_MAX_PROCESSOR_NAME];
int myrank; // Rank of processor
int numprocs; // Number of processes
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Get_processor_name(processorName,&nameLen);
MPI_Status status;
time_t t;
srand((unsigned)time(NULL)+myrank*numprocs+nameLen);
SubD s;
compRange(&s, myrank, numprocs);
compDynRange(&s);
MPI_Finalize();
return 0;
}
I use a for-loop which seems highly inefficient to me. Here I compute the maximum value of every row of all lists one after the other.
But can I use MPI_Allreduce without that for-loop?
I already tried that instead of the for-loop which does not work.
MPI_Allreduce(&s->range, &rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
Can someone give me a hint how I can do that?
As already hinted in comment, the error you had in you code was that instead of passing the arrays containing your send and receive buffers, you were passing some pointers to them. I imagine that this error was simply coming fro the change from a single element used initially (like &s->range[r]) which was perfectly correct, to the full array by just removing the indexed access (ie &s->range) which was wrong.
So as explained, using:
MPI_Allreduce(s->range, rangeForAll, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD)
just does the trick. However, since you want to get the results into the s->range arrays rather than the temporary rangeFarAll ones, you'd better off not defining the later at all, and use the MPI_IN_PLACE keyword as sending parameter and s->range as receiving one. The call becomes:
MPI_Allreduce(MPI_IN_PLACE, s->range, s->numprocs+1, MPI_INT, MPI_MAX, MPI_COMM_WORLD)
and s->range acts both as sending and receiving buffer. Therefore, the final results will all be in the s->range buffers after the call, sparing you the need of doing the copy explicitly.

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.

Resources