MPI send struct and recive array - c

I have a problem with communication in my program. The program sends to process structure and together count search function. I can not properly receive feedback from the search function, which returns an array.
My struct:
struct sets{
int array[R];
};
Some struct initialization
tab[0].array[0] = 1;
tab[0].array[1] = 2;
tab[0].array[2] = 3;
Send information:
obl = calloc(q, sizeof(int));
MPI_Scatter(tab, q, MPI_INT, obl, q, MPI_INT, 0, MPI_COMM_WORLD);
counter = search(tab, setX);
And recive and send:
if(rank == 0)
{
for(i=1; i < p; i++)
{
//edit
MPI_Recv(counter+i, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &status);
}
int k;
for(k=0; k<N; k++)
{
if(*(counter+k) == 5)
{
printf("Set number %d is the same \n", k);
}
if(*(counter+k) == 1)
{
printf("Set number %d have at least one identical \n", k);
}
if(*(counter+k) == 2)
{
printf("No elements in set number %d \n", k);
}
}
}
else
{
MPI_Send(counter, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
}
and search function:
int * search(struct sets *tab, int *setX)
{
int result[N];
int i; //pass=0
for(i=0; i<N; i++)
{
result[i]=0;
}
for(i=0; i<N; i++)
{
int j, k;
int counter=0;
for(j=0; j<R; j++)
{
for(k=0; k<R; k++)
{
if(tab[i].array[j] == setX[k])
{
counter++;
}
}
//printf("Conuter: %d - i: %d \n", counter,i);
if(counter == R)
{
result[i]=5;
//the same sets
}
else if(counter > 1 && counter < R)
{
result[i]=1;
//
}
else if(counter == 0)
{
result[i]=2;
//0
}
}
printf("counter: %d\n", counter);
}
return result;
}
Sequencial run it works ok, but when I run this code on 4 processors result is bad. I think the problem is in send and revice data in MPI functions.
Full code: http://pastebin.com/5c8Jn3sa
EDIT:
Resuts:
./a.out - sequential
counter: 10
counter: 9
counter: 0
counter: 10
counter: 6
counter: 6
Set number 0 is the same
Set number 1 have at least one identical
No elements in set number 2
Set number 3 is the same
Set number 4 have at least one identical
Set number 5 have at least one identical
mpiecex -np 2 ./a.out - 2 process
counter: 100
counter: 100
counter: 100
counter: 100
counter: 100
counter: 100
counter: 10
counter: 9
counter: 0
counter: 10
counter: 6
counter: 6
No elements in set number 0
Set number 1 have at least one identical
Set number 2 have at least one identical
mpiexec has a bad results

Related

MPI_Gather doesn't receive data

The program should take two cmd line arguments, N = the number of items each worker should generate, and H = the highest value in the range of random numbers generate by each worker. Each worker makes a list of those random values and then the BigList is where I'm trying to gather them all back to but nothing shows up in the array of BigList. So for example:
Running mpirun -np 3 a.out 4 20 gets:
RANK: 1 --- NUM: 18
RANK: 1 --- NUM: 6
RANK: 1 --- NUM: 12
RANK: 1 --- NUM: 10
RANK: 2 --- NUM: 9
RANK: 2 --- NUM: 3
RANK: 2 --- NUM: 6
RANK: 2 --- NUM: 5
and BigList is empty when I'd expect it to get composed of every num listed above.
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char* argv[]){
double t1, t2;
MPI_Init(&argc, &argv);
int rank;
int wsize;
int N = 10, H = 5;
int num, k, i;
int locarr[25];
int bigList[300];
srand(time(NULL));
if(argc > 1){
N = atoi(argv[1]);
H = atoi(argv[2]);
}
t1 = MPI_Wtime();
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &wsize);
if( rank == 0){
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&H, 1, MPI_INT, 0, MPI_COMM_WORLD);
}
else{
for(i = 0; i < N; i++){
locarr[i] = (((rand() % H) + 1) / rank);
printf("RANK: %d --- NUM: %d\n", rank, locarr[i]);
}
}
MPI_Gather(&locarr, N, MPI_INT, bigList, N, MPI_INT, 0, MPI_COMM_WORLD);
if( rank == 0){
printf("BigList: ");
for(k = 0; k < (rank * N); k++){
printf(" %d", bigList[k]);
}
printf("\n");
}
t2 = MPI_Wtime();
// printf("\nMPI_Wtime(): %f\n", t2 - t1);
MPI_Finalize();
return 0;
}
Let me expand the comment of Gilles Gouaillardet,
MPI_Gather call is written correctly. To get the expected results, two changes need to be done.
MPI_Bcast is a collective operation. All processes should call it. So the code should be:
if( rank == 0){
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&H, 1, MPI_INT, 0, MPI_COMM_WORLD);
}
else{
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&H, 1, MPI_INT, 0, MPI_COMM_WORLD);
for(i = 0; i < N; i++){
locarr[i] = (((rand() % H) + 1) / rank);
printf("RANK: %d --- NUM: %d\n", rank, locarr[i]);
}
}
Also, rank 0 prints the contents of the bigList. But in for loop, the loop condition is k<rank*N, for rank 0 this will always be false (k<0*N) as a result loop won't be executed and no value will be printed. So it should be world size (wsize) instead of rank.
if( rank == 0){
printf("BigList: ");
for(k = 0; k < wsize*N; k++){
printf(" %d", bigList[k]);
}
printf("\n");
}
The print function was printing some extra garbage values in the BigList array. Instead replacing the print part of the code with this would solve the error
if (rank == 0)
{
printf("BigList: ");
for (k = N; k < wsize * N; k++)
{
printf(" %d", bigList[k]);
}
printf("\n");
}
The full code for the problem is-
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
double t1, t2;
MPI_Init(&argc, &argv);
int rank;
int wsize;
int N = 10, H = 5;
int num, k, i;
int locarr[25];
int bigList[300];
srand(time(NULL));
if (argc > 1)
{
N = atoi(argv[1]);
H = atoi(argv[2]);
}
t1 = MPI_Wtime();
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &wsize);
if (rank == 0)
{
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&H, 1, MPI_INT, 0, MPI_COMM_WORLD);
}
else
{
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&H, 1, MPI_INT, 0, MPI_COMM_WORLD);
for (i = 0; i < N; i++)
{
locarr[i] = (((rand() % H) + 1) / rank);
printf("RANK: %d --- NUM: %d\n", rank, locarr[i]);
}
}
MPI_Gather(&locarr, N, MPI_INT, bigList, N, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0)
{
printf("BigList: ");
for (k = N; k < wsize * N; k++)
{
printf(" %d", bigList[k]);
}
printf("\n");
}
MPI_Finalize();
return 0;
}

MPI Broadcast and Reduce

I have this code below..
When I run this with mpiexec -n 2
I get output in the console log like The input sequence is as follows: 0 1 2 3
I'm trying to get an output sequence of 0 2 6 12
which is an addition of PartialResult in the forloop
This is the result of the forloop, and I get this for each process, so when I run with 2 processes, this gets printed out twice.
Partial result in forloop: 0
Partial result in forloop: 1
Partial result in forloop: 3
Partial result in forloop: 6
I want to add them so that the output sequence (when rank == 0), this return 0 2 6 12. Can this be achieved after MPI_Reduce step?
Below is the entire C code.
int main(void)
{
int my_rank, comm_sz;
int i;
int Count = 4;
int Number[4];
int PartialResult = 0;
int Result;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if(my_rank == 0)
{
printf("The input sequence is as follows: \n");
for (i = 0; i < Count; i++)
{
Number[i] = i;
printf("%d ", Number[i]);
}
printf("\n");
}
// Process 0 sends data to all of the processes
MPI_Bcast(Number, Count, MPI_INT, 0, MPI_COMM_WORLD);
for (i = 0; i < Count; i++)
{
Number[i] += my_rank;
PartialResult += Number[i];
printf("\n");
printf("Partial result in forloop: %d \n", PartialResult);
}
MPI_Reduce(&PartialResult, &Result, 1, MPI_INT, MPI_PROD, 0, MPI_COMM_WORLD);
printf("partial result after reduce: %d \n", PartialResult);
// Print out the result
if (my_rank == 0) {
printf("\n");
for (i = 0; i < Count; i++) {
printf("\n");
printf("\n");
printf("Result[i]: %d \n", Result[i]);
}
}
MPI_Finalize();
return 0;
}

How to print this series?(1 \n 2 3 \n 4 5 6 \n 7 8 9 10... ... ...)

I am trying to print the following series: 1 2 3 4 5 6 7 8 9 10 ... ... ...The input of my program contains a single integer n, which determines the number of lines to print.
I've tried to code it but got the following output:
12 33 4 54 5 6 7... ... ...
#include<stdio.h>
int main()
{
int n,i,j,t,m;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
for(j=i,t=1;t<=i;j++,t++)
{
printf("%d ",j);
}
printf("\n");
}
}
To print those numbers, you'll want a counter that starts at 1, increases by 1 every print and is never reset by anything. Adjust your loop like this:
int main()
{
int n, i, j, t = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= i; j++, t++)
{
printf("%d ", t);
}
printf("\n");
}
}
Note how t is set to 1, and just gets increased by t++ without resetting like you previously did. Also, you should be printing t, not j.
You should maintain separate counters for the numbers and the number of numbers per line.
int nr = 1, target;
int nrsperline = 1, i;
scanf("%d", &target);
while (nr <= target) {
for (i = 0; i < nrsperline; i++) {
printf("%d ", nr++);
}
printf("\n");
nrsperline++;
}

Parellel Programming: How can I apply 'MPI_Gather' or 'MPI_Scatter' instead of 'MPI_Isend' and 'MPI_Recv'

This is my code counting prime numbers, I want to use only collective communication among those processes. However, I got error when I changed my code using 'MPI_Scatter' and 'MPI_Gather' instead of MPI_Recv and MPI_Isend. What should I change for it?
This is my original code:
MPI_Request req;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if( my_rank == 0){
printf("Input(50-1000) : ");
fflush(stdout);
scanf("%d",&w);
for(i=0; i<w; i++) data[i] = i+1;
}
MPI_Bcast(&w, 1, MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(data, w, MPI_INT,0,MPI_COMM_WORLD);
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
MPI_Isend(&i,1,MPI_INT,0,0,MPI_COMM_WORLD,&req);
}
if(my_rank == 0){
int j = 0;
for( j = 1; j < p; j++){
MPI_Recv(&i,1,MPI_DOUBLE,MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&status);
printf("Process %d : There are %d prime numbers\n",status.MPI_SOURCE,i );
}
}
MPI_Finalize();
}
And the output is:
Input(50-1000) : 50
Process 1 : There are 5 prime numbers
Process 2 : There are 4 prime numbers
Process 3 : There are 2 prime numbers
Process 4 : There are 4 prime numbers
Here is the part where I changed my code:
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data_send[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
MPI_Scatter(data_send,1,MPI_INT,data_recv,1,MPI_INT,0,MPI_COMM_WORLD);
}
here is how you can use MPI_Gather()
int * results;
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
} else {
results = (int *)malloc(p * sizeof(int));
}
MPI_Gather(&i, 1, MPI_INT, results, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(my_rank == 0){
int j = 0;
for( j = 1; j < p; j++){
printf("Process %d : There are %d prime numbers\n",j, results[j]);
}
free(results);
}
note you can arrange this algo in order to also do computations on rank 0, and hence use p MPI tasks instead of p-1
MPI_Scatter is a collective operation and need to be called by all ranks. Same thing goes for MPI_Gather.
The means that: MPI_Scatter call should be moved outside of the if block in your code (similarly for MPI_Gather).
You can find an example here.

Code that splits an array and counts repetitions

The following code nearly works but for some reason the first value in the array printed is also the last value and also the first value of the next set of data that is printed. I know that might sound confusing.
Here is the code
#include <stdio.h>
#define MAX 288
int nThArrayPrint(double prev, int count, int i, double *array) {
int j = MAX*i;
for (i = j; i <(j+MAX); i++) {
if (array[i] == prev) {
count++;
} else {
printf("%.4lf= %d\t", prev, count);
prev = array[i];
count = 1;
}
}
return count;
}
int main()
{
FILE *fp;
fp = fopen("C:\\Users\\niall\\Desktop\\question2.txt", "r");
double array[MAX * 5]; // Initializes array to all 0.0s
int i, x, j, count;
double prev = 0;
if (fp != NULL) {
for (i = 0; i < MAX * 5; i++) { //Load values from file into an array
fscanf(fp, "%lf", &array[i]);
}
fclose(fp);
prev = array[0]; // initialize
for (i = 0; i < 5; i++){
count = 1;
printf("\tNumber of times each value is repeated for the %dth set of values\n\n", i+1);
count = nThArrayPrint(prev, count, i, array);
prev = array[MAX*i];
printf("%.4lf= %d\n\n", prev, count);
}
} else {
printf("There was a probem opening the file.");
}
}
modify the below segment of the code
prev = array[0]; // initialize
for (i = 0; i < 5; i++){
count = 1;
printf("\tNumber of times each value is repeated for the %dth set of values\n\n", i+1);
count = nThArrayPrint(prev, count, i, array);
prev = array[MAX*i];
printf("%.4lf= %d\n\n", prev, count);
}
into
count = 1;
for (i = 0; i < 5; i++){
printf("\tNumber of times each value is repeated for the %dth set of values\n\n", i+1);
for (j = i*MAX; j < (i*MAX)+MAX; j++) {
if (array[j] == array[j+1]) {
count++;
} else {
printf("%.4lf= %d\n", array[j], count);
count = 1;
}
}
if(count > 1){
printf("%.4lf= %d\n", array[j], count-1);
count = 1;
}
}
Tested with below input with MAX as 9
12 12 12 12 12 1 1 1 1 4 5 5 6 7 8 9 3 3 3 2 2 2 1 1 1 1 1 1 6 62 2.2 2.2 2.2 3.2 3.2 3.2 3.2 22 22 22 22 22 1 22 22 22 22
output:
Number of times each value is repeated for the 1th set of values
12.0000= 5
1.0000= 4
Number of times each value is repeated for the 2th set of values
4.0000= 1
5.0000= 2
6.0000= 1
7.0000= 1
8.0000= 1
9.0000= 1
3.0000= 2
Number of times each value is repeated for the 3th set of values
3.0000= 1
2.0000= 3
1.0000= 5
Number of times each value is repeated for the 4th set of values
1.0000= 1
6.0000= 1
62.0000= 1
2.2000= 3
3.2000= 3
Number of times each value is repeated for the 5th set of values
3.2000= 1
22.0000= 5
1.0000= 1
22.0000= 2

Resources