Discussion:
MPI_Newbie: Can I use MPI_Send in a for loop to distribute segments of data, even though MPI_Recv is outside the for loop?
(too old to reply)
unknown
2004-10-29 18:27:07 UTC
Permalink
Dear all,
thanks to Andreas Pommer for helping me out in my earlier problem.

Now I have another problem. basically I'm using a for loop to distribute
different pieces of a matrix to other processes including itself. I know
it's definitely a common occurence (data decomposition).
but my code below sends and receive correctly if mpirun -np 1 but for
mpirun -np 2, process 0 receives correctly but process 1 receives zeros.
likewise for higher values. I know i'm giving MPI_Send the correct
values cos it prints fine and it returns the errorvalue 0. I tried using
MPI_Ssend then it just hangs there. So basically my MPI_Recv works for
process 0 but not for process > 0.

Basic question about MPI, I compile one program that contains checks for
the process rank it's on. then every process will run the same program,
ignoring parts which doesn't not involve it's own process rank, right?
so when debugging programs, if it is clear that for process 0 it is
running that code fragment, process 1,2, ... should run that fragment
too right?

How? Been perusing google groups already and the internet but no avail.
maybe not using proper search terms. please help? thanks for your time
and patience.

tylim

/*---------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#define MAT_M 4
#define MAT_N 3
/* BLOCK DECOMPOSITION MACROS taken from
* Micheal J Quinn, Parallel programming in C with MPI and OpenMP
* International Edition 2003 Chapter 5.4.3 pg 120 */
/* first or lowest index controlled by process (id)*/
#define BLOCK_LOW(id,p,n) ((id)*(n)/(p))
/* last, or highest index controlled by the process (id) */
#define BLOCK_HIGH(id,p,n) (BLOCK_LOW((id)+1,p,n) - 1)
/* number of elements controlled by process (id) */
#define BLOCK_SIZE(id,p,n) (BLOCK_LOW((id)+1,p,n)-BLOCK_LOW(id,p,n))
/* rank of process controlling element (index) of array */
#define BLOCK_OWNER(index,p,n) (((p)*((index)+1)-1)/(n))


int main (int argc, char *argv[])
{
int i,j,k, tag = 99, errorcode;
int id; /* Process Rank */
int p; /* Number of processes */
int mat_A[MAT_M][MAT_N]={1,2,3,4,5,6,7,8,9,10,11,12};
int *mat_B, *recv_block, *sending;
int begin_row, end_row, rows_per_process, total_elements;
MPI_Status status;

MPI_Init( &argc, &argv);
MPI_Comm_rank( MPI_COMM_WORLD, &id);
MPI_Comm_size( MPI_COMM_WORLD, &p);

/* allocate and send process k's share of the matrix
* runs only on process 0 */
if(id==0) {
for( k=0;k<p;k++) {
begin_row = BLOCK_LOW(k,p,MAT_M);
end_row = BLOCK_HIGH(k,p,MAT_M);
rows_per_process = BLOCK_SIZE(k,p,MAT_M);
total_elements = BLOCK_SIZE(k,p,MAT_M)*MAT_N;
printf("id %d begin %d end %d total elements
%d\n",k,begin_row,end_row, total_elements);
sending = (int *) malloc(total_elements*sizeof(int));
if(sending==NULL) {
printf("Error:malloc\n");
MPI_Finalize();
}
/* a(no of columns * i + j) = a[i][j]*/
printf("Send to Process %d from \n",k,id);
for(i=begin_row; i<=end_row; i++)
for(j=0;j<MAT_N;j++) {
sending[MAT_N*i+j]=mat_A[i][j];
printf("%d ",sending[MAT_N*i+j]);
if((j+1)%MAT_N==0) printf("\n");
}
errorcode = MPI_Send(
sending,total_elements,MPI_INT,k,tag,MPI_COMM_WORLD);
printf("errorcode: %lu\n",errorcode);
free(sending);
}
}
/* figure out this process share of mat_A
* runs on all process including process 0 */
begin_row = BLOCK_LOW(id,p,MAT_M);
end_row = BLOCK_HIGH(id,p,MAT_M);
rows_per_process = BLOCK_SIZE(id,p,MAT_M);
total_elements = BLOCK_SIZE(id,p,MAT_M)*MAT_N;
printf("process %d begin at row %d end at row %d total elements
%d\n",id,begin_row,end_row, total_elements);
recv_block = (int *) malloc(total_elements*sizeof(int));
if(recv_block==NULL) {
printf("Error:malloc\n");
MPI_Finalize();
}
MPI_Recv( recv_block,total_elements,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
/* refers to local index of matrix A*/
printf("Recv Process %d\n",id);
fflush(stdout);
for(i=0;i<total_elements;i++) {
printf("%d ",recv_block[i]);
if((i+1)%MAT_N==0) printf("\n");
}
free(recv_block);

MPI_Finalize();
}
/*---------------------------------------------------------*/
Randy
2004-10-29 23:17:03 UTC
Permalink
Post by unknown
Dear all,
thanks to Andreas Pommer for helping me out in my earlier problem.
Now I have another problem. basically I'm using a for loop to distribute
different pieces of a matrix to other processes including itself. I know
it's definitely a common occurence (data decomposition).
but my code below sends and receive correctly if mpirun -np 1 but for
mpirun -np 2, process 0 receives correctly but process 1 receives zeros.
likewise for higher values. I know i'm giving MPI_Send the correct
values cos it prints fine and it returns the errorvalue 0. I tried using
MPI_Ssend then it just hangs there. So basically my MPI_Recv works for
process 0 but not for process > 0.
Why not use one of the collective routines to distribute the data, like
MPI_Alltoall? It's often used for array redistribution.

Point-to-point MPI calls are a pain to coordinate among multiple processes,
especially when the number of processes might change from run to run, and so,
the communication identifiers and perhaps even the pattern must change. As
such, it's often best to bundle up all your outgoing or incoming messages into
bunches of nonblocking calls, which makes your code more readable, as in:

// start up multiple nonblocking sends
for (to = 0; to < num_procs; to++)
MPI_Isend( outmsg[to], ..., to, ..., &out_handles[to]);

// start up multiple nonblocking receives
for (from = 0; from < num_procs; from++)
MPI_Irecv( inmsg[from], ..., from, ..., &in_handles[from]);

// confirm that all sends have gone out
MPI_Waitall( to, out_handles, ...);

// wait for all receives to come in
MPI_Waitall( from, in_handles, ...);

// now all sends and receives have completed, and you can move on
...
Post by unknown
Basic question about MPI, I compile one program that contains checks for
the process rank it's on. then every process will run the same program,
ignoring parts which doesn't not involve it's own process rank, right?
so when debugging programs, if it is clear that for process 0 it is
running that code fragment, process 1,2, ... should run that fragment
too right?
Yes. All MPI processes will execute all parts of an MPI program after MPI_Init
and before MPI_Finalize, unless you insert conditionals into your code,
directing each MPI process to execute a different section of code, as in:

MPI_Comm_rank( MPI_COMM_WORLD, &my_rank);
if (my_rank == 0)
only process 0 does something;
else if (my_rank == 1)
only process 1 does something;
...

Another way to have each MPI process do something different is to compile
several different executables, and then run multiple executables as part of a
single MPI job.

For example, to run six MPI processes, 1 of prognameX, 3 of prognameY, and 2 of
prognameZ, you could invoke mpirun with:

mpirun -np 1 prognameX -np 3 prognameY -np 2 prognameZ

However, just because this is possible doesn't make it a good idea. IMHO,
heterogeneous (MIMD) jobs are a lot harder to debug than homogeneous (SPMD) jobs.

Randy
Post by unknown
How? Been perusing google groups already and the internet but no avail.
maybe not using proper search terms. please help? thanks for your time
and patience.
tylim
/*---------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#define MAT_M 4
#define MAT_N 3
/* BLOCK DECOMPOSITION MACROS taken from
* Micheal J Quinn, Parallel programming in C with MPI and OpenMP
* International Edition 2003 Chapter 5.4.3 pg 120 */
/* first or lowest index controlled by process (id)*/
#define BLOCK_LOW(id,p,n) ((id)*(n)/(p))
/* last, or highest index controlled by the process (id) */
#define BLOCK_HIGH(id,p,n) (BLOCK_LOW((id)+1,p,n) - 1)
/* number of elements controlled by process (id) */
#define BLOCK_SIZE(id,p,n) (BLOCK_LOW((id)+1,p,n)-BLOCK_LOW(id,p,n))
/* rank of process controlling element (index) of array */
#define BLOCK_OWNER(index,p,n) (((p)*((index)+1)-1)/(n))
int main (int argc, char *argv[])
{
int i,j,k, tag = 99, errorcode;
int id; /* Process Rank */
int p; /* Number of processes */
int mat_A[MAT_M][MAT_N]={1,2,3,4,5,6,7,8,9,10,11,12};
int *mat_B, *recv_block, *sending;
int begin_row, end_row, rows_per_process, total_elements;
MPI_Status status;
MPI_Init( &argc, &argv);
MPI_Comm_rank( MPI_COMM_WORLD, &id);
MPI_Comm_size( MPI_COMM_WORLD, &p);
/* allocate and send process k's share of the matrix
* runs only on process 0 */
if(id==0) {
for( k=0;k<p;k++) {
begin_row = BLOCK_LOW(k,p,MAT_M);
end_row = BLOCK_HIGH(k,p,MAT_M);
rows_per_process = BLOCK_SIZE(k,p,MAT_M);
total_elements = BLOCK_SIZE(k,p,MAT_M)*MAT_N;
printf("id %d begin %d end %d total elements
%d\n",k,begin_row,end_row, total_elements);
sending = (int *) malloc(total_elements*sizeof(int));
if(sending==NULL) {
printf("Error:malloc\n");
MPI_Finalize();
}
/* a(no of columns * i + j) = a[i][j]*/
printf("Send to Process %d from \n",k,id);
for(i=begin_row; i<=end_row; i++)
for(j=0;j<MAT_N;j++) {
sending[MAT_N*i+j]=mat_A[i][j];
printf("%d ",sending[MAT_N*i+j]);
if((j+1)%MAT_N==0) printf("\n");
}
errorcode = MPI_Send(
sending,total_elements,MPI_INT,k,tag,MPI_COMM_WORLD);
printf("errorcode: %lu\n",errorcode);
free(sending);
}
}
/* figure out this process share of mat_A
* runs on all process including process 0 */
begin_row = BLOCK_LOW(id,p,MAT_M);
end_row = BLOCK_HIGH(id,p,MAT_M);
rows_per_process = BLOCK_SIZE(id,p,MAT_M);
total_elements = BLOCK_SIZE(id,p,MAT_M)*MAT_N;
printf("process %d begin at row %d end at row %d total elements
%d\n",id,begin_row,end_row, total_elements);
recv_block = (int *) malloc(total_elements*sizeof(int));
if(recv_block==NULL) {
printf("Error:malloc\n");
MPI_Finalize();
}
MPI_Recv(
recv_block,total_elements,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
/* refers to local index of matrix A*/
printf("Recv Process %d\n",id);
fflush(stdout);
for(i=0;i<total_elements;i++) {
printf("%d ",recv_block[i]);
if((i+1)%MAT_N==0) printf("\n");
}
free(recv_block);
MPI_Finalize();
}
/*---------------------------------------------------------*/
--
Randy Crawford http://www.ruf.rice.edu/~rand rand AT rice DOT edu
Loading...