MPI_Scatter is receiving wrong values - c

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.

Related

MPI Array undeclared

I am attaching a Minimal Reproducing Example of the error that I am facing in a large code. Say I have 2 processes, P0 and P1. I am declaring an array int arr[2] inside P0 and storing a value in arr[0]. Then I am redeclaring int arr[2] for P1 only, but whenever I am trying to access it inside P1, I am getting ‘arr’ undeclared (first use in this function) 37 | arr[1]=1; error. I am attaching the code here.
#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
double sTime, eTime, time,max_time;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank) ;
MPI_Comm_size(MPI_COMM_WORLD, &size);
int r=0, c;
if(myrank==0)
{
int arr[2];
arr[0]=1;
}
if(myrank!=0)
{
int arr[2];
}
if(myrank==1)
{
arr[1]=2;
MPI_Send(&arr[1], 1 , MPI_INT, 0 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
}
MPI_Status status[2];
if(myrank==0)
{
MPI_Recv(&arr[1],1 , MPI_INT, 1 /*src*/ , 100 /*tag*/, MPI_COMM_WORLD,&status[1]);
for(int i=0;i<2;i++)
{
printf(" %d",arr[i]);
}
}
MPI_Finalize();
return 0;
}
To prevent this error I have tried declaring int arr[2] inside
if(myrank==1){
int arr[2];
arr[1]=2;
MPI_Send(arr[1], 1 , MPI_INT, 0 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
}
But this time I get this error,
‘arr’ undeclared (first use in this function)
47 | MPI_Recv(arr[0],1 , MPI_INT, 1 /src/ , 100 /tag/, MPI_COMM_WORLD,&status[1]);
I am not able to get what is wrong here. Any suggestions will be really helpful.
That error is because you declared a variable inside a if statement and you want to used outside that if. In C that is not possible, when you do:
if(myrank==0)
{
int arr[2];
arr[0]=1;
}
the array int arr[2]; will only exist in the scope of that if statement. Therefore, if you try to access it outside it leads to a compilation error.
To get around you can either declare int arr[2] outside the if statement (but then all MPI process would allocated), or declare a pointer to int outside and only allocate memory for that pointer for the process that you want, namely:
int *arr = NULL;
if(myrank==0)
{
arr = malloc(sizeof(int) * 2);
arr[0]=1;
}
when the array is not longer needed do not forget to free it:
free(arr);
Another option (that works in your example) is to rearrange the code so that you have all the code related with the one process in one if branch, and the code from the other process in another if branch, namely:
#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
double sTime, eTime, time,max_time;
MPI_Status status[2];
MPI_Comm_rank(MPI_COMM_WORLD, &myrank) ;
MPI_Comm_size(MPI_COMM_WORLD, &size);
int r=0, c;
if(myrank==0)
{
int arr[2];
arr[0]=1;
MPI_Recv(&arr[1],1 , MPI_INT, 1 /*src*/ , 100 /*tag*/, MPI_COMM_WORLD,&status[1]);
for(int i=0;i<2;i++)
printf(" %d",arr[i]);
}
if(myrank==1)
{
int arr[2];
arr[1]=2;
MPI_Send(&arr[1], 1 , MPI_INT, 0 /*dest*/ , 100 /*tag*/ , MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}

Open MPI Waitall() Segmentation Fault

I'm new with MPI and I'm trying to develop a non-blocking programm (with Isend and Irecv). The functionality is very basic (it's educational):
There is one process (rank 0) who is the master and receives messages from the slaves (rank 1-P). The master only receives results.
The slaves generates an array of N random numbers between 0 and R and then they do some operations with those numbers (again, it's just for educational purpose, the operations don't make any sense)
This whole process (operations + send data) is done M times (this is just for comparing different implementations; blocking and non-blocking)
I get a Segmentation Fault in the Master process when I'm calling the MPI_waitall() funcion
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#include <math.h>
#include <time.h>
#define M 1000 //Number of times
#define N 2000 //Quantity of random numbers
#define R 1000 //Max value of random numbers
double SumaDeRaices (double*);
int main(int argc, char* argv[]) {
int yo; /* rank of process */
int p; /* number of processes */
int dest; /* rank of receiver */
/* Start up MPI */
MPI_Init(&argc, &argv);
/* Find out process rank */
MPI_Comm_rank(MPI_COMM_WORLD, &yo);
/* Find out number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Request reqs[p-1];
MPI_Status stats[p-1];
if (yo == 0) {
int i,j;
double result;
clock_t inicio,fin;
inicio = clock();
for(i = 0; i<M; i++){ //M times
for(j = 1; j<p; j++){ //for every slave
MPI_Irecv(&result, sizeof(double), MPI_DOUBLE, j, i, MPI_COMM_WORLD, &reqs[j-1]);
}
MPI_Waitall(p-1,reqs,stats); //wait all slaves (SEG_FAULT)
}
fin = clock()-inicio;
printf("Tiempo total de ejecucion %f segundos \n", ((double)fin)/CLOCKS_PER_SEC);
}
else {
double* numAleatorios = (double*) malloc( sizeof(double) * ((double) N) ); //array with numbers
int i,j;
double resultado;
dest=0;
for(i=0; i<M; i++){ //again, M times
for(j=0; j<N; j++){
numAleatorios[j] = rand() % R ;
}
resultado = SumaDeRaices(numAleatorios);
MPI_Isend(&resultado,sizeof(double), MPI_DOUBLE, dest, i, MPI_COMM_WORLD,&reqs[p-1]); //send result to master
}
}
/* Shut down MPI */
MPI_Finalize();
exit(0);
} /* main */
double SumaDeRaices (double* valores){
int i;
double sumaTotal = 0.0;
//Raices cuadradas de los valores y suma de estos
for(i=0; i<N; i++){
sumaTotal = sqrt(valores[i]) + sumaTotal;
}
return sumaTotal;
}
There are several issues with your code. First and foremost in your Isend you pass &resultado several times without waiting until previous non-blocking operation finishes. You are not allowed to reuse the buffer you pass to Isend before you make sure the operation finishes.
Instead I recommend you using normal Send, because in contrast to synchronous send (SSend) normal blocking send returns as soon as you can reuse the buffer.
Second, there is no need to use message tags. I recommend you to just set tag to 0. In terms of performance it is simply faster.
Third, the result shouldn't be a simple variable, but an array of size at least (p-1)
Fourth, I do not recommend you to allocate arrays on stack, like MPI_Request and MPI_Status if the size is not a known small number. In this case the size of array is (p-1), so you better use malloc for this data structure.
Fifth, if you do not check status, use MPI_STATUSES_IGNORE.
Also instead of sizeof(double) you should specify number of items (1).
But of course the absolutely best version is just to use MPI_Gather.
Moreover, generally there is no reason not to run computations on the root node.
Here is slightly rewritten example:
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#include <math.h>
#include <time.h>
#define M 1000 //Number of times
#define N 2000 //Quantity of random numbers
#define R 1000 //Max value of random numbers
double SumaDeRaices (double* valores)
{
int i;
double sumaTotal = 0.0;
//Raices cuadradas de los valores y suma de estos
for(i=0; i<N; i++) {
sumaTotal = sqrt(valores[i]) + sumaTotal;
}
return sumaTotal;
}
int main(int argc, char* argv[]) {
int yo; /* rank of process */
int p; /* number of processes */
/* Start up MPI */
MPI_Init(&argc, &argv);
/* Find out process rank */
MPI_Comm_rank(MPI_COMM_WORLD, &yo);
/* Find out number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &p);
double *result;
clock_t inicio, fin;
double *numAleatorios;
if (yo == 0) {
inicio = clock();
}
numAleatorios = (double*) malloc( sizeof(double) * ((double) N) ); //array with numbers
result = (double *) malloc(sizeof(double) * p);
for(int i = 0; i<M; i++){ //M times
for(int j=0; j<N; j++) {
numAleatorios[j] = rand() % R ;
}
double local_result = SumaDeRaices(numAleatorios);
MPI_Gather(&local_result, 1, MPI_DOUBLE, result, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); //send result to master
}
if (yo == 0) {
fin = clock()-inicio;
printf("Tiempo total de ejecucion %f segundos \n", ((double)fin)/CLOCKS_PER_SEC);
}
free(numAleatorios);
/* Shut down MPI */
MPI_Finalize();
} /* main */

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.

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