How to scatter multiple variables in an array for MPI_Scatter - arrays

I am currently struggling to equally distribute an array with 8 integers to 2 integers per 4 processors. I used MPI_Bcast to let every processors to know there are total array of 8 and each of those will have 2 integers array called "my_input".
MPI_Bcast(&totalarray,1,MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);
MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );
//MPI_Barrier (MPI_COMM_WORLD);
printf("\n my input is %d & %d and rank is %d \n" , my_input[0], my_input[1] , rank);
However after scattering, I see the print function cannot print the 'rank' but all the integers from the 8 integers array. How should I program in order to equally distribute the number of arrays to other processors from root?
Here is my full code (it is just for testing a total of 8 integers, therefore scanf I will enter '8'):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"
int main(int argc, char *argv[])
{
//initailise MPI
MPI_Init(&argc, &argv);
//Variable to identify processor and total number of processors
int rank, size;
int my_input[0];
//initailse total array variable
int totalarray =0;
//initialise memory array
int* input;
//range of random number
int upper = 100, lower = 0;
//declare processor rank
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
//declare total size of processor
MPI_Comm_size(MPI_COMM_WORLD, &size);
//let root gather N elements from user
if (rank == 0)
{
printf("Enter a number from 1 to 1000: ");
fflush(stdout);
int number;
//ask user to input number of elements
scanf("%d",&number);
printf("Your number is %d\n",number);
//Fill the array to power of 2
int totalarray = pow(2, ceil(log(number)/log(2)));
input[totalarray];
my_input[totalarray/size];
//allocate memory for the array
input = malloc(totalarray * sizeof(int) );
//Add randomise number until N elements
for(int i =0; i<=totalarray ; i++)
{
if( i<number)
{
input[i] = (rand() % (upper - lower + 1)) + lower; ;
}
//padding zero to the extra elements
else if(number <= i < totalarray)
{
input[i] = 0;
}
}
//confirm the input array
printf("the input is: ");
for(int i =0; i < totalarray ; i++)
{
printf( "%d ", input[i]);
}
}
MPI_Bcast(&totalarray,1,MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);
MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );
//MPI_Barrier (MPI_COMM_WORLD);
printf("\n my input is %d & %d and rank is %d \n" , my_input[0], my_input[1] , rank);
MPI_Finalize();
return 0;
}

I used MPI_Bcast to let every processors to know there are total array
of 8 and each of those will have 2 integers array called "my_input".
Yes, that makes sense.
However after scattering, I see the print function cannot print the
'rank' but all the integers from the 8 integers array. How should I
program in order to equally distribute the number of arrays to other
processors from root?
You have some issues with your code. For instance, you declare the variables my_input, totalarray, and input as:
int my_input[0];
...
int totalarray =0;
...
int* input;
and then within if (rank == 0) you redefine them again:
int totalarray = pow(2, ceil(log(number)/log(2)));
input[totalarray];
my_input[totalarray/size];
input = malloc(totalarray * sizeof(int) );
This is not correct, alternatively what you can do is to declare both arrays as int*, namely:
int *my_input;
int *input;
then allocate their space as soon as you know how many elements there will be in each of those arrays.
The input array can be allocated right after the user has inserted the size of that array:
//ask user to input number of elements
scanf("%d",&number);
printf("Your number is %d\n",number);
input = malloc(totalarray * sizeof(int));
and the my_input array after the master process has broadcast the input size to the other processes:
MPI_Bcast(&totalarray, 1, MPI_INT, 0, MPI_COMM_WORLD);
int *my_input = malloc((totalarray/size) * sizeof(int));
For the variable totalarray just do not declare again within if (rank == 0). Because if you do so, then int totalarray = pow(2, ceil(log(number)/log(2))); will be a different variable that will only exist in the scope of the if (rank == 0).
The second MPI_Bcast call
MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);
is unless, since you want to
to equally distribute total 8 integers in an array to 2 integers for
4 processors.
and not that every process has the entire contend of the my_input array of the master process.
For that you need the MPI_Scatter which you do. However, instead of
MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );
do not hardcode the size of the inputs, because if you want to test with different input sizes and/or with a different number of processes the code will not work, do the following instead:
int size_per_process = totalarray/size;
MPI_Scatter (input, size_per_process , MPI_INT, my_input, size_per_process , MPI_INT, 0, MPI_COMM_WORLD );
The loop for(int i =0; i<=totalarray ; i++) should actually be for(int i =0; i< totalarray ; i++), otherwise you are getting out of boundaries of the array input. Personal opinion, but I think that the adding of the random values logic reads better this way:
for(int i =0; i < number ; i++)
input[i] = (rand() % (upper - lower + 1)) + lower;
for(int i = number; i < totalarray; i++)
input[i] = 0;
The final code would look like the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"
int main(int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int rank, size;
int *input;
int totalarray;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank == 0){
printf("Enter a number from 1 to 1000: ");
fflush(stdout);
int number;
scanf("%d",&number);
printf("Your number is %d\n",number);
totalarray = pow(2, ceil(log(number)/log(2)));
input = malloc(totalarray * sizeof(int));
int upper = 100, lower = 0;
for(int i = 0; i < number ; i++)
input[i] = (rand() % (upper - lower + 1)) + lower;
for(int i = number; i < totalarray; i++)
input[i] = 0;
printf("the input is: ");
for(int i =0; i < totalarray ; i++)
printf( "%d ", input[i]);
}
MPI_Bcast(&totalarray, 1, MPI_INT, 0, MPI_COMM_WORLD);
int size_per_process = totalarray / size;
int *my_input = malloc(size_per_process * sizeof(int));
printf("SIZE PER %d\n", size_per_process);
MPI_Scatter (input, size_per_process, MPI_INT, my_input, size_per_process, MPI_INT, 0, MPI_COMM_WORLD );
printf("\n my input is %d & %d and rank is %d \n" , my_input[0], my_input[1] , rank);
MPI_Finalize();
return 0;
}
The last print can also be made to be more generic by printing the entire my_input rather than just the first two positions.

Related

how can i run MPI program in windows

I tried running it with microsoft MPI but its not generating desired output.
#include <stdio.h>
#include <math.h>
#include "mpi.h"
double function(double x) {
// Define the function to be integrated here
return x * sin(x);
}
int main(int argc, char *argv[]) {
double a, b, h, sum, x;
int n, p, rank, size, i;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank == 0) {
printf("Enter the number of subintervals (n): ");
scanf("%d", &n);
printf("Enter the number of processes (p): ");
scanf("%d", &p);
}
// Broadcast the inputs to all processes
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&p, 1, MPI_INT, 0, MPI_COMM_WORLD);
a = 0.0;
b = 1.0;
h = (b - a) / n;
sum = 0.0;
// Divide the work among the processes
int interval_per_process = n / p;
int start = rank * interval_per_process;
int end = (rank + 1) * interval_per_process - 1;
for (i = start; i <= end; i++) {
x = a + h * (i + 0.5);
sum = sum + function(x);
}
sum = sum * h;
// Reduce the results from all processes to process 0
double global_sum;
MPI_Reduce(&sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (rank == 0) {
printf("The value of the integral is %.6lf\n", global_sum);
}
MPI_Finalize();
return 0;
}
So I need output like : It should ask for subintervals and processes and then give the final result i.e answer of integration using the midpoint rule.
But instead when i run it displays nohting and if enter any number it skips the scanner part and directly produce the output
I need a compiler

Caught signal 11 (Segmentation fault: address not mapped to object at address 0xff00000107)

Im practising in parallel programming using MPI and i developed a programm that is calculating the average and how many numbers of the array are greater or fewer than the average. Unfortunately when im trying to run it on linux ubuntu system i get this *Caught signal 11 (Segmentation fault: address not mapped to object at address 0xff00000107), backtrace(tid: 5699).
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int main(int argc, char** argv){
int p, plithos, i, k, count_max,count_min, sunexeia;
int *pinakas;
int *final_res;
int loc_matrix[100];
int loc_num;
int my_rank;
int root, local_sum, sum, j, source;
int tag1=50;
int tag2=60;
int tag3=70;
int tag4=80;
float average;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
if (my_rank == 0) {
printf("please give the size of the array: ");
scanf("%d", &plithos);
pinakas = (int *) malloc(plithos * sizeof(int));
for (i = 0; i < plithos; i++) {
printf("Give the %d number: ", i);
scanf("%d", &pinakas[i]);
}
}
root = 0;
MPI_Bcast(&plithos, 1, MPI_INT, root, MPI_COMM_WORLD); // here we are sending the size of the array to the processors
loc_num = plithos / p;
root = 0;
MPI_Scatter(&pinakas, loc_num, MPI_INT, &loc_matrix, loc_num, MPI_INT, root, MPI_COMM_WORLD); // here we are sending the amount of tasks that every processor must have
local_sum=0; // here all processors will calculate their sums
if (my_rank == 0) {
int start = 0;
int end = loc_num;
for (i = start; i < end; i++){
local_sum += pinakas[i];
}
}
else{
int start = my_rank * loc_num;
int end = my_rank + loc_num;
for (i = start; i < end; i++){
local_sum += pinakas[i];
}
}
MPI_Reduce(&local_sum, &sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); //here with the reduce we are caclulating all the sums from all processors
if (my_rank == 0) { // processor 0 finds the average
average = (double)sum / plithos;
printf("The average is: %f\n", average);
}
root = 0;
MPI_Bcast(&average, 1, MPI_FLOAT, root, MPI_COMM_WORLD); //edo stelnoume tin mesi timi stis upoloipes diergasies
if (my_rank = 0){ //edo h diergasia 0 tha upologisei posa stoixeia exoun min kai max > tou average
for(i=0; i<plithos; i++){
if(pinakas[i]> average){
count_max = count_max +1;
}
if(pinakas[i]< average){
count_min = count_min +1;
}
}
printf("To plithos ton stoixeion pou exoun megaluteri timi apo tin mesi timi einai: %d", count_max);
printf("To plithos ton stoixeion pou exoun mikroteri timi apo tin mesi timi einai: %d", count_min);
}
MPI_Finalize();
}

Passing submatrices from master to slaves MPI

I'm trying to learn MPI and I've run into the following problem in one of my courses:
Consider a matrix A of dimensions n * n in which each element is an integer. Given 2 pair of indices (i1,j1) and (i2,j2) find the submatrix of such dimensions in matrix A for which it's elements sum is maximum.
I'd like some help on how to pass the submatrices to the processes. Should I calculate first how many submatrices (s) are in the matrix and send to each process N/s? How would I send the submatrices?
Some skeleton code I wrote:
#include<mpi.h>
#include<stdio.h>
#include<math.h>
#include<assert.h>
#include<iostream>
using namespace std;
#pragma comment (lib, "msmpi.lib")
enum CommunicationTag
{
COMM_TAG_MASTER_SEND_TASK,
COMM_TAG_MASTER_SEND_TERMINATE,
COMM_TAG_SLAVE_SEND_RESULT,
};
void print_matrix(int mat[10][10], int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
}
int main(int argc, char *argv[]) {
//0. Init part, finding rank and number of processes
int numprocs, rank, rc;
rc = MPI_Init(&argc, &argv);
if (rc != MPI_SUCCESS) {
printf("Error starting MPI program. Terminating \n");
MPI_Abort(MPI_COMM_WORLD, rc);
}
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
printf("I'm rank %d. Num procs %d\n", rank, numprocs); fflush(stdout);
//1. different machine code
if (rank == 0)
{
int n;
scanf("%d", &n);
int i1, i2, j1, j2;
scanf("%d%d%d%d", &i1, &i2, &j1, &j2);
int mat[10][10];
//init data
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
mat[i][j] = (rand() % 100) - 50; //init random between -50 and 49
}
print_matrix(mat, n);
//here; how do I pass the submatrices to the processes?
for (int i = 1; i < numprocs; i++) {
MPI_Send(&i1, 1, MPI_INT, i, COMM_TAG_MASTER_SEND_TASK, MPI_COMM_WORLD);
MPI_Send(&i2, 1, MPI_INT, i, COMM_TAG_MASTER_SEND_TASK, MPI_COMM_WORLD);
MPI_Send(&j1, 1, MPI_INT, i, COMM_TAG_MASTER_SEND_TASK, MPI_COMM_WORLD);
MPI_Send(&j2, 1, MPI_INT, i, COMM_TAG_MASTER_SEND_TASK, MPI_COMM_WORLD);
//here; how do I pass the submatrices to the processes?
}
}
else {
//if slave ...
}
system("Pause");
}
The first step is to stop thinking about how to use MPI_Send(). The basic solution is to use MPI_Bcast() to transmit A to all the MPI processes.
Then divide the work up (no need to communicate for this, the same dividing logic can run in each process). Compute the sums within each MPI process, and collect them in the main process using MPI_Gather(). Choose the largest and you're done.
It really only requires two MPI operations: Bcast to distribute the input data to all processes, and Gather to centralize the results.
Note that all MPI processes need to execute the collective operations together in lockstep. You only need if (rank == 0) to know which process should load the matrix and analyze the Gathered results.

How to count the number of times a random number between '0-6' prints in a given array?

I am trying to count the number of times a number from 0-6 appears in a given array that has values generated from a random number generator. However, my code just returns '0' instead of counting the number of times the number appears in the array. I am new to this, can someone help me?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int array[7];
int i;
int zero=0;
int one=0;
int two=0;
int three=0;
int four=0;
int five=0;
int six=0;
for (i=0; i<=7; i++)
array[i] = i;
srand( (unsigned)time( NULL ) );
for (i=0; i<=7; i++)
{
int index1 = i;
int index2 = rand()%7;
int temp;
temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
if(i==48){zero++;}
else{if(i==49){one++;}
else{if(i==50){two++;}
else{if(i==51){three++;}
else{if(i==52){four++;}
else{if(i==53){five++;}
else{if(i==54){six++;}
}}}}}}}
for (i=0; i<=7; i++){
printf("array[%d] = %d\n",i,array[i]);}
printf("Number of times each number came up is:\n");
printf("Zero:%d\n", zero);
printf("One:%d\n", one);
printf("Two:%d\n", two);
printf("Three:%d\n", three);
printf("Four:%d\n", four);
printf("Five:%d\n", five);
printf("Six:%d\n", six);
return(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_RAND_NUMBERS (1000)
int main(void)
{
int i;
int randValue = 0;
int array[7] = {0}; // initialize array counters to 0
srand( (unsigned)time( NULL ) ); // initialize rand() function
for (i=0; i<MAX_RAND_NUMBERS; i++)
{
randValue = rand()%7;
array[randValue]++;
} // end for
printf("total number of random numbers (limited range: 0...6): %d\n", MAX_RAND_NUMBERS );
printf("Number of times each of the limited range numbers occurred is:\n");
for (i=0; i<7; i++)
{
printf("number: %d, occurrence count: %d\n",i,array[i]);
}
return(0);
} // end function: main
First of all, as mentioned above in a comment your statement :
for (i=0; i<=7; i++)
It has a error because in reality, it starts from 0 and goes all the way to 7, INCLUDING 7. That means you actually have 8 positions ( 0 -> 7) instead of (0 -> 6), which is what you desire to achieve. So it should be:
for (i=0; i < 7; i++)
That is not however the major problem. You said in your question :
I am trying to count the number of times a number from 0-6 appears in a given array that has values generated from a random number generator
In the following code :
for (i=0; i< 7; i++)
array[i] = i;`
Your array elements will not be random numbers because you assign them very determined numbers. More specifically, your array will be something like this:
[0, 1, 2, 3, 4, 5, 6].
To assign random numbers to an array I would do something like this:
srand(time(NULL));
for(i = 0; i < 7; ++i) {
array[i] = rand()%7; // this will generate numbers in the range of [0,6]
}
Ok, now you have an array of random numbers just as you wanted. So let's try to count them. I would try to implement an apparition array:
int apparition[7] = {0}; // this statement will initialize all values to 0
for(i = 0; i < 7; ++i) {
apparition[array[i]]++;
}
The code above does the following thing: it iterates over the array of numbers, and for each value it increments that specific apparition array element. Suppose you have array[i] = 6, then apparition[6] = 1, so you have counted one apparition.
Your code :
if(i==48){zero++;}
else{if(i==49){one++;}
else{if(i==50){two++;}
else{if(i==51){three++;}
else{if(i==52){four++;}
else{if(i==53){five++;}
else{if(i==54){six++;}
I suppose that you considered 48 to be the ASCII representation for 0, right?
That is not correct, because the 0 you see in that table is '0' which is actually a char value, not an integer value.
Instead you should have done
if(array[i] == 0) {zero++};
If you choose to implement the apparition array, you can print it like this:
for(i = 0; i < 7; ++) {
printf("%d appears: %d times\n", i, apparition[i]);
}
Hope it helps :-)

MPI_Scatter and MPI_Gather dont work

Hallo Iam trying to make a simlpe parralel program in C language uing MPI. Program should find maximum in array. Root process should send chunks of array to all processes using MPI_Scatter and then gather results by MPI_Gather. When I run the program i get general error like this:
Perhaps this Unix error message will help:
Unix errno: 14
Bad address
I know that there is some problem with MPI_Scatter and MPI_Gather or with the values I am sending to this functions.
I was trying to find the solution, but I found nothing what could be useful.
Here is my code:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 9
int max(int *buf, int N){
int i;
int value = 0;
for(i=0; i<N; i++){
if (buf[i]>value){
value = buf[i];
}
}
return value;
}
int main(int argc, char** argv)
{ int size, rank;
int slave;
int *buf;
int *buf1;
int *buf2;
int i, n, value;
MPI_Status status;
/* Initialize MPI */
MPI_Init(NULL, NULL);
/*
* Determine size in the world group.
*/
MPI_Comm_size(MPI_COMM_WORLD, &size);
if ((BUFSIZE % size) != 0) {
printf("Wrong Bufsize ");
return(0);
}
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank==0) {
buf = (int *)malloc(BUFSIZE*sizeof(int));
buf2 = (int *)malloc(size*sizeof(int));
printf("\n Generated array: \n");
for(i=0; i<BUFSIZE; i++){
buf[i] = rand() % 20;
printf("%d, ", buf[i]);
}
printf("\n");
printf("\n Sending values to processes:");
printf("\n -----------------------------");
}
buf1 = (int *)malloc((BUFSIZE/size)*sizeof(int));
MPI_Scatter(buf, BUFSIZE/size, MPI_INT, buf1, BUFSIZE/size, MPI_INT, 0, MPI_COMM_WORLD);
value = max(&buf1[0], BUFSIZE/size);
printf("\n Max from rocess %d : %d \n", rank, max(&buf1[0], BUFSIZE/size));
MPI_Gather(&value, 1, MPI_INT, buf2, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0){
printf("\n Max value: %d", max(&buf2[0], size));
}
MPI_Finalize();
return(0);
}
Initialize your pointers to NULL, and track them.
use buf1 instead of &buf1[0], is more clear.
free your buffers before MPI_Finalize() with:
if(bufferPionter != NULL) free(bufferPionter);
If something is wrong with a pointer will crash in the free call. In the max function, If all your numbers are less than zero the maximun is zero. i fix that.
int max(int *buf, int N){
int i;
int value = N? buf[0] : 0;
for(i=0; i<N; i++){
if (buf[i]>value){
value = buf[i];
}
}
return value;
}
Best regards!

Resources