I am trying to parallelize a grayscale filter for BMP image, my function get stuck when trying to send data from a pixel array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mpi.h"
#define MASTER_TO_SLAVE_TAG 1 //tag for messages sent from master to slaves
#define SLAVE_TO_MASTER_TAG 10 //tag for messages sent from slaves to master
#pragma pack(1)
struct image {
struct fileHeader fh;
struct imageHeader ih;
pixel *array;
};
struct fileHeader {
//blablabla...
};
struct imageHeader {
//blablabla...
};
typedef struct
{
unsigned char R;
unsigned char G;
unsigned char B;
}pixel;
void grayScale_Parallel(struct image *im, int size, int rank)
{
int i,j,lum,aux,r;
pixel tmp;
int total_pixels = (*im).ih.width * (*im).ih.height;
int qty = total_pixels/(size-1);
int rest = total_pixels % (size-1);
MPI_Status status;
//printf("\n%d\n", rank);
if(rank == 0)
{
for(i=1; i<size; i++){
j = i*qty - qty;
aux = j;
if(rest != 0 && i==size-1) {qty=qty+rest;} //para distrubuir toda la carga
printf("\nj: %d qty: %d rest: %d\n", j, qty, rest);
//it gets stuck here,it doesn't send the data
MPI_Send(&(*im).array[j], qty*3, MPI_BYTE, i, MASTER_TO_SLAVE_TAG, MPI_COMM_WORLD);
MPI_Send(&aux, 1, MPI_INT, i, MASTER_TO_SLAVE_TAG+1, MPI_COMM_WORLD);
MPI_Send(&qty, 1, MPI_INT, i, MASTER_TO_SLAVE_TAG+2, MPI_COMM_WORLD);
printf("\nSending to node=%d, sender node=%d\n", i, rank);
}
}
else
{
MPI_Recv(&aux, 1, MPI_INT, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG+1, MPI_COMM_WORLD,&status);
MPI_Recv(&qty, 1, MPI_INT, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG+2, MPI_COMM_WORLD,&status);
pixel *arreglo = (pixel *)calloc(qty, sizeof(pixel));
MPI_Recv(&arreglo[0], qty*3, MPI_BYTE, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG, MPI_COMM_WORLD,&status);
//PROCESS RECEIVED PIXELS...
//SEND to ROOT PROCESS
}
if (rank==0){
//RECEIVE DATA FROM ALL PROCESS
}
}
int main(int argc, char *argv[])
{
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Status status;
int op=1;
char filename_toload[50];
int bright_number=0;
struct image image2;
if (rank==0)
{
printf("File to load: \n");
scanf("%s", filename_toload);
loadImage(&image2, filename_toload);
}
while(op != 0)
{
if (rank==0)
{
printf("Welcome to example program!\n\n");
printf("\t1.- GrayScale Parallel Function\n");
printf("\t2.- Call another Function\n");
printf("\t0.- Exit\n\t");
printf("\n\n\tEnter option:");
scanf("%d", &op);
}
//Broadcast the user's choice to all other ranks
MPI_Bcast(&op, 1, MPI_INT, 0, MPI_COMM_WORLD);
switch(op)
{
case 1:
grayScale_Parallel(&image2, size, rank);
MPI_Barrier(MPI_COMM_WORLD);
printf("GrayScale applied successfully!\n\n");
break;
case 2:
function_blabla();
printf("Function called successfully\n\n");
break;
}
}
MPI_Finalize();
return 0;
}
I think the MPI_Send function can't read the array of pixels, but is strange because i can print the pixels.
Any idea?
To elaborate more on Soravux's answer, you should change the order of your MPI_Send calls (note the changed MASTER_TO_SLAVE_TAGs) as follows to avoid deadlocks:
MPI_Send(&aux, 1, MPI_INT, i, MASTER_TO_SLAVE_TAG, MPI_COMM_WORLD);
MPI_Send(&qty, 1, MPI_INT, i, MASTER_TO_SLAVE_TAG+1, MPI_COMM_WORLD);
MPI_Send(&(*im).array[j], qty*3, MPI_BYTE, i, MASTER_TO_SLAVE_TAG+2, MPI_COMM_WORLD);
These calls need to be matched by the following sequence of MPI_Recv calls
MPI_Recv(&aux, 1, MPI_INT, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG, MPI_COMM_WORLD,&status);
MPI_Recv(&qty, 1, MPI_INT, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG+1, MPI_COMM_WORLD,&status);
pixel *arreglo = (pixel *)calloc(qty, sizeof(pixel));
MPI_Recv(&arreglo[0], qty*3, MPI_BYTE, MPI_ANY_SOURCE, MASTER_TO_SLAVE_TAG+2, MPI_COMM_WORLD,&status);
Hope this answers your question.
The order in which you call MPI_Send and MPI_Recv is important. You must ensure your calls are always in the same order since these functions are blocking. A call to MPI_Send will not return as long as its corresponding (same tag) MPI_Recv counterpart is not executed on the destination. This may cause deadlocks otherwise.
Related
i'm trying send packed structure by MPI_Bsend(). Something i'm doing wrong and i cannot find solution.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mpi.h"
#define SIZE 10
struct car {
int id;
int vmax;
char marka[SIZE];
char model[SIZE];
};
int main(int argc, char **argv) {
int i;
int rank, size;
double t1, t2;
struct car BMW, BMW2;
BMW.id = 1;
strcpy(BMW.marka, "BMW");
strcpy(BMW.model, "szybki");
BMW.vmax = 199;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
int rozmiar, packet_size, msg_size, position = 0,tag;
void *bufor;
MPI_Pack_size(2, MPI_INT, MPI_COMM_WORLD, &rozmiar);
packet_size = rozmiar;
MPI_Pack_size(2 * SIZE, MPI_CHAR, MPI_COMM_WORLD, &rozmiar);
packet_size += rozmiar;
msg_size = 2 * packet_size + MPI_BSEND_OVERHEAD;
bufor = (void *)malloc(msg_size);
MPI_Buffer_attach(bufor, msg_size);
t1 = MPI_Wtime();
if (rank == 0) {
tag = 0;
for(i=1;i<size;i++){
MPI_Pack(&BMW.id,1, MPI_INT, bufor, msg_size, &position, MPI_COMM_WORLD);
MPI_Pack(&BMW.vmax,1, MPI_INT, bufor, msg_size, &position, MPI_COMM_WORLD);
MPI_Pack(&BMW.model,SIZE, MPI_CHAR, bufor, msg_size, &position, MPI_COMM_WORLD);
MPI_Pack(&BMW.marka,SIZE, MPI_CHAR, bufor, msg_size, &position, MPI_COMM_WORLD);
MPI_Bsend(bufor,position,MPI_PACKED,i,tag,MPI_COMM_WORLD);
}
} else {
MPI_Recv(bufor,msg_size,MPI_PACKED,0,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
position = 0;
MPI_Unpack(bufor, msg_size, &position, &BMW2.id, 1, MPI_INT, MPI_COMM_WORLD);
MPI_Unpack(bufor, msg_size, &position, &BMW2.vmax, 1, MPI_INT, MPI_COMM_WORLD);
MPI_Unpack(bufor, msg_size, &position, &BMW2.model, SIZE, MPI_CHAR, MPI_COMM_WORLD);
MPI_Unpack(bufor, msg_size, &position, &BMW2.marka, SIZE, MPI_CHAR, MPI_COMM_WORLD);
printf("rank = %d | BMW id: %d, marka: %s, model: %s, vmax: %d \n",rank, BMW2.id, BMW2.marka, BMW2.model, BMW2.vmax);
}
t2 = MPI_Wtime();
MPI_Buffer_detach(&bufor, &msg_size);
MPI_Finalize();
if (i == size)
printf("Elapsed time is %.15f\n", t2 - t1 );
return(0);
}
Error:
====================================================================
BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
PID 25637 RUNNING AT debian
EXIT CODE: 11
================================================================
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault
(signal 11)
You are using the buffered mode of MPI incorrectly. The buffer you give to MPI via MPI_Buffer_attach is supposed to be used by MPI internally. Do not use the buffered MPI interface, it is very rarely useful and very difficult to get right.
Just remove the MPI_Buffer_ and use MPI_Send instead of MPI_Bsend and you are on the right track. MPI_Pack can be a bit clumsy, you may want to look insto custom datatypes (MPI_Type_create_struct) instead. If you have a homogeneous system, you can also send the raw bytes of the struct car.
Ok, so the aim of the game here is for each one of 64 processors (representing an 8x8 grid) to generate a random number (between 0 and 1), and give process zero a string representing the complete situation. For example grid:
[0,1,0,1]
[1,1,1,1]
[0,0,0,0]
would ultimately get have string '0101111000' for a 4x3.
Each process can only communicate with the ones above and to their left.
To do this, I have each process receive a string of all numbers on its right (if it's not on the far right), add its number to the front of the string and send it to the left.
If the process is on the far left, it also receives a string from the process below it (not including bottom left, rank 56), the description of the state of all nodes below that rank .It joins its own value, the left and bottom strings, and sends it up.
All far left nodes begin their row's string.
My attempted code is below:
#include <stdio.h>
#include "mpi.h"
#include <string.h>
#include <stdlib.h>
int farLeft(int rank){// edit
if (rank%8==0){
return 1;
}
return 0;
}
int farRight(int rank){// edit
if (rank%8==7){
return 1;
}
return 0;
}
int main(argc, argv)
int argc;
char **argv;
{
char inputList[100],myWhisp[100],snum[256];
int rank,value;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
srand(rank);
value = rand() % 2;
sprintf(snum, "%d", value);
strcpy(myWhisp,snum);
if (farLeft(rank)){
MPI_Recv(inputList, strlen(inputList)+1, MPI_CHAR, rank+1, 0, MPI_COMM_WORLD, &status);
strcat(snum,inputList);
strcpy(myWhisp,snum);
if (rank !=56){
MPI_Recv(inputList, strlen(inputList)+1, MPI_CHAR, rank+8, 0, MPI_COMM_WORLD, &status);//rank48 crashes here
strcat(myWhisp,inputList);
}
strcpy(inputList,myWhisp);
if(rank==0){
printf("%s\n",inputList);
}
else{
MPI_Send(inputList, strlen(inputList)+1, MPI_CHAR, rank-8, 0, MPI_COMM_WORLD);
}
}
else if (farRight(rank)){
strcpy(inputList,myWhisp);
MPI_Send(inputList, strlen(inputList)+1, MPI_CHAR, rank-1, 0, MPI_COMM_WORLD);
}
else{
MPI_Recv(inputList, strlen(inputList)+1, MPI_CHAR, rank+1, 0, MPI_COMM_WORLD, &status);
strcat(snum,inputList);
strcpy(inputList,snum);
MPI_Send(inputList, strlen(inputList)+1, MPI_CHAR, rank-1, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
I'm getting a truncation error with rank 48, the second last rank in the far left. This happens on the receive function below if(rank != 56). So there's something wrong with the way I send/ receive inputString I guess...
Thanks very much.
You're passing the count parameter of MPI_Recv as strlen(inputList)+1, but inputList was never initialised. You probably want sizeof(inputList) here.
Is it possible to do an MPI_Sendrecv exchange where one side does not know the rank of the other? If not, what is the best way to do that (my next guess would just be a pair of sends and recvs)?
For example in C if I want to exchange integers between rank 0 and some other rank would this type of thing work?:
MPI_Status stat;
if(rank){
int someval = 0;
MPI_Sendrecv(&someval, 1, MPI_INT, 0, 1, &recvbuf, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &stat);
}else{
int someotherval = 1;
MPI_Sendrecv(&someotherval, 1, MPI_INT, MPI_ANY_SOURCE, someotherval, &recvbuf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &stat);
}
EDIT:
Looks like it is not possible. I whipped up the following as a sort of wrapper to add the functionality that I need.
void slave_sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int source, int recvtag, MPI_Status *status){
MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, MPI_COMM_WORLD);
MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, MPI_COMM_WORLD, status);
}
void anon_sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
int sendtag, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int recvtag, MPI_Status *status){
int anon_rank;
MPI_Recv(recvbuf, recvcount, recvtype, MPI_ANY_SOURCE, recvtag, MPI_COMM_WORLD, status);
anon_rank = status -> MPI_SOURCE;
MPI_Send(sendbuf, sendcount, sendtype, anon_rank, sendtag, MPI_COMM_WORLD);
}
EDIT 2: Based on Patrick's answer it looks like the slave_sendrecv function above is not needed, you can just use regular MPI_Sendrecv on the end that knows who it's sending to.
Short answer: No.
The standard does not allow the use of MPI_ANY_SOURCE as the destination rank dest in any send procedure. This make sense, since you can not send a message without knowing the destination.
The standard however does permit you to pair a MPI_Sendrecv with regular MPI_Send/MPI_Recv:
A message sent by a send-receive operation can be received by a regular receive operation
or probed by a probe operation; a send-receive operation can receive a message sent
by a regular send operation.
In your case, process 0 will have to first receive, and then answer:
MPI_Status stat;
if(rank){
int someval = 0;
MPI_Sendrecv(&someval, 1, MPI_INT, 0, 1, &recvbuf, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &stat);
}else{
int someotherval = 1;
MPI_Recv(&recvbuf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &stat);
// answer to process `stat.MPI_SOURCE` using `someotherval` as tag
MPI_Send(&someotherval, 1, MPI_INT, stat.MPI_SOURCE, someotherval, MPI_COMM_WORLD);
}
I've been having a bug in my code for some time and could not figure out yet how to solve it.
What I'm trying to achieve is easy enough: every worker-node (i.e. node with rank!=0) gets a row (represented by 1-dimensional arry) in a square-structure that involves some computation. Once the computation is done, this row gets sent back to the master.
For testing purposes, there is no computation involved. All that's happening is:
master sends row number to worker, worker uses the row number to calculate the according values
worker sends the array with the result values back
Now, my issue is this:
all works as expected up to a certain size for the number of elements in a row (size = 1006) and number of workers > 1
if the elements in a row exceed 1006, workers fail to shutdown and the program does not terminate
this only occurs if I try to send the array back to the master. If I simply send back an INT, then everything is OK (see commented out line in doMasterTasks() and doWorkerTasks())
Based on the last bullet point, I assume that there must be some race-condition which only surfaces when the array to be sent back to the master reaches a certain size.
Do you have any idea what the issue could be?
Compile the following code with: mpicc -O2 -std=c99 -o simple
Run the executable like so: mpirun -np 3 simple <size> (e.g. 1006 or 1007)
Here's the code:
#include "mpi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MASTER_RANK 0
#define TAG_RESULT 1
#define TAG_ROW 2
#define TAG_FINISHOFF 3
int mpi_call_result, my_rank, dimension, np;
// forward declarations
void doInitWork(int argc, char **argv);
void doMasterTasks(int argc, char **argv);
void doWorkerTasks(void);
void finalize();
void quit(const char *msg, int mpi_call_result);
void shutdownWorkers() {
printf("All work has been done, shutting down clients now.\n");
for (int i = 0; i < np; i++) {
MPI_Send(0, 0, MPI_INT, i, TAG_FINISHOFF, MPI_COMM_WORLD);
}
}
void doMasterTasks(int argc, char **argv) {
printf("Starting to distribute work...\n");
int size = dimension;
int * dataBuffer = (int *) malloc(sizeof(int) * size);
int currentRow = 0;
int receivedRow = -1;
int rowsLeft = dimension;
MPI_Status status;
for (int i = 1; i < np; i++) {
MPI_Send(¤tRow, 1, MPI_INT, i, TAG_ROW, MPI_COMM_WORLD);
rowsLeft--;
currentRow++;
}
for (;;) {
// MPI_Recv(dataBuffer, size, MPI_INT, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status);
MPI_Recv(&receivedRow, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
if (rowsLeft == 0)
break;
if (currentRow > 1004)
printf("Sending row %d to worker %d\n", currentRow, status.MPI_SOURCE);
MPI_Send(¤tRow, 1, MPI_INT, status.MPI_SOURCE, TAG_ROW, MPI_COMM_WORLD);
rowsLeft--;
currentRow++;
}
shutdownWorkers();
free(dataBuffer);
}
void doWorkerTasks() {
printf("Worker %d started\n", my_rank);
// send the processed row back as the first element in the colours array.
int size = dimension;
int * data = (int *) malloc(sizeof(int) * size);
memset(data, 0, sizeof(size));
int processingRow = -1;
MPI_Status status;
for (;;) {
MPI_Recv(&processingRow, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
if (status.MPI_TAG == TAG_FINISHOFF) {
printf("Finish-OFF tag received!\n");
break;
} else {
// MPI_Send(data, size, MPI_INT, 0, TAG_RESULT, MPI_COMM_WORLD);
MPI_Send(&processingRow, 1, MPI_INT, 0, TAG_RESULT, MPI_COMM_WORLD);
}
}
printf("Slave %d finished work\n", my_rank);
free(data);
}
int main(int argc, char **argv) {
if (argc == 2) {
sscanf(argv[1], "%d", &dimension);
} else {
dimension = 1000;
}
doInitWork(argc, argv);
if (my_rank == MASTER_RANK) {
doMasterTasks(argc, argv);
} else {
doWorkerTasks();
}
finalize();
}
void quit(const char *msg, int mpi_call_result) {
printf("\n%s\n", msg);
MPI_Abort(MPI_COMM_WORLD, mpi_call_result);
exit(mpi_call_result);
}
void finalize() {
mpi_call_result = MPI_Finalize();
if (mpi_call_result != 0) {
quit("Finalizing the MPI system failed, aborting now...", mpi_call_result);
}
}
void doInitWork(int argc, char **argv) {
mpi_call_result = MPI_Init(&argc, &argv);
if (mpi_call_result != 0) {
quit("Error while initializing the system. Aborting now...\n", mpi_call_result);
}
MPI_Comm_size(MPI_COMM_WORLD, &np);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
}
Any help is greatly appreciated!
Best,
Chris
If you take a look at your doWorkerTasks, you see that they send exactly as many data messages as they receive; (and they receive one more to shut them down).
But your master code:
for (int i = 1; i < np; i++) {
MPI_Send(¤tRow, 1, MPI_INT, i, TAG_ROW, MPI_COMM_WORLD);
rowsLeft--;
currentRow++;
}
for (;;) {
MPI_Recv(dataBuffer, size, MPI_INT, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status);
if (rowsLeft == 0)
break;
MPI_Send(¤tRow, 1, MPI_INT, status.MPI_SOURCE, TAG_ROW, MPI_COMM_WORLD);
rowsLeft--;
currentRow++;
}
sends np-2 more data messages than it receives. In particular, it only keeps receiving data until it has no more to send, even though there should be np-2 more data messages outstanding. Changing the code to the following:
int rowsLeftToSend= dimension;
int rowsLeftToReceive = dimension;
for (int i = 1; i < np; i++) {
MPI_Send(¤tRow, 1, MPI_INT, i, TAG_ROW, MPI_COMM_WORLD);
rowsLeftToSend--;
currentRow++;
}
while (rowsLeftToReceive > 0) {
MPI_Recv(dataBuffer, size, MPI_INT, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status);
rowsLeftToReceive--;
if (rowsLeftToSend> 0) {
if (currentRow > 1004)
printf("Sending row %d to worker %d\n", currentRow, status.MPI_SOURCE);
MPI_Send(¤tRow, 1, MPI_INT, status.MPI_SOURCE, TAG_ROW, MPI_COMM_WORLD);
rowsLeftToSend--;
currentRow++;
}
}
Now works.
Why the code doesn't deadlock (note this is deadlock, not a race condition; this is a more common parallel error in distributed computing) for smaller message sizes is a subtle detail of how most MPI implementations work. Generally, MPI implementations just "shove" small messages down the pipe whether or not the receiver is ready for them, but larger messages (since they take more storage resources on the receiving end) need some handshaking between the sender and the receiver. (If you want to find out more, search for eager vs rendezvous protocols).
So for the small message case (less than 1006 ints in this case, and 1 int definitely works, too) the worker nodes did their send whether or not the master was receiving them. If the master had called MPI_Recv(), the messages would have been there already and it would have returned immediately. But it didn't, so there were pending messages on the master side; but it didn't matter. The master sent out its kill messages, and everyone exited.
But for larger messages, the remaining send()s have to have the receiver particpating to clear, and since the receiver never does, the remaining workers hang.
Note that even for the small message case where there was no deadlock, the code didn't work properly - there was missing computed data.
Update: There was a similar problem in your shutdownWorkers:
void shutdownWorkers() {
printf("All work has been done, shutting down clients now.\n");
for (int i = 0; i < np; i++) {
MPI_Send(0, 0, MPI_INT, i, TAG_FINISHOFF, MPI_COMM_WORLD);
}
}
Here you are sending to all processes, including rank 0, the one doing the sending. In principle, that MPI_Send should deadlock, as it is a blocking send and there isn't a matching receive already posted. You could post a non-blocking receive before to avoid this, but that's unnecessary -- rank 0 doesn't need to let itself know to end. So just change the loop to
for (int i = 1; i < np; i++)
tl;dr - your code deadlocked because the master wasn't receiving enough messages from the workers; it happened to work for small message sizes because of an implementation detail common to most MPI libraries.
If I am using blocking send and recv (MPI_send(), MPI_recv()), how to make theese two operation indefinite? Like they are repeating all over again?
Sample code:
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
MPI_Comm_rank (MPI_COMM_WORLD,&rank);
if(rank==0){
rc=MPI_Send(msg,1,MPI_CHAR,1,1,MPI_COMM_WORLD);
rc=MPI_Recv(msg,1,MPI_CHAR,1,1,MPI_COMM_WORLD,&status);
}else{
rc=MPI_Recv(msg,1,MPI_CHAR,0,0,MPI_COMM_WORLD,&status);
rc=MPI_Send(msg,1,MPI_CHAR,0,0,MPI_COMM_WORLD);
}
I have tried to put before if(rank==0) -> while(1) and it did the job, but I see there are several sends, then several recieves and I want it like - send(0), receive(1), send(1), recieve(0).
You can code a ring of send-receive operations easily by using MPI_Sendrecv:
int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag, void *recvbuf, int recvcount,
MPI_Datatype recvtype, int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
As you can see it's only a condensed version of a MPI_Send and a MPI_Recv, but it comes handy when all the process needs either to send and receive something.
The following code works for any number of processes (you can adapt it to your needs):
CODE UPDATE #1 (Using MPI_Sendrecv)
#include <stdio.h>
#include <unistd.h>
#include <mpi.h>
int main (int argc, char *argv[])
{
int size, rank, value, next, prev, sendval, recval;
double t0, t;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
value = 5;
if (size > 1)
{
next = (rank + 1)% size;
prev = (size+rank - 1)% size;
sendval = value + rank;
for (;;)
{
t0 = MPI_Wtime();
MPI_Sendrecv(&sendval, 1, MPI_INT, next, 1, &recval, 1, MPI_INT, prev, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
t = MPI_Wtime();
fprintf(stdout, "[%d of %d]: Sended %d to process %d, Received %d from process %d (MPI_SendRecv Time: %f)\n",rank, size-1, sendval, next, recval, prev, (t - t0));
}
}
MPI_Finalize();
return 0;
}
CODE UPDATE #2 (Using separate MPI_Send/MPI_Recv)
#include <stdio.h>
#include <unistd.h>
#include <mpi.h>
int main (int argc, char *argv[])
{
int size, rank, value, next, prev, sendval, recval;
double s0, s, r, r0;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
value = 5;
if (size > 1)
{
next = (rank + 1)% size;
prev = (size+rank - 1)% size;
sendval = value + rank;
for (;;)
{
s0 = MPI_Wtime();
MPI_Send(&sendval, 1, MPI_INT, next, 1, MPI_COMM_WORLD);
s = MPI_Wtime();
fprintf(stdout, "[%d of %d]: Sended %d to process %d (MPI_Send Time: %f)\n", rank, size-1, sendval, next, s-s0);
r0 = MPI_Wtime();
MPI_Recv(&recval, 1, MPI_INT, prev, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
r = MPI_Wtime();
fprintf(stdout, "[%d of %d]: Received %d from process %d (MPI_Recv Time: %f)\n", rank, size-1, recval, prev, r-r0);
}
}
MPI_Finalize();
return 0;
}
Running Example
mpicc -o sendrecv sendrecv.c
mpirun -n 2 sendrecv
[0 of 1]: Sended 5 to process 1, Received 6 from process 1 (MPI_SendRecv Time: 0.000121)
[1 of 1]: Sended 6 to process 0, Received 5 from process 0 (MPI_SendRecv Time: 0.000068)
...
It is impossible to give an accurate answer to that without seeing at least the basic layout of your code. Generally, you would place the Send and Receive operations inside an infinite loop. Or, if you're hard pressed for optimal communication costs (or simply feeling adventurous), you could use persistent Send and Receive.