How to MPI_SEND and MPI_RECV - c

i have an this input file .txt where there are sequences:
NAMEOFSEQUENCE1/SEQUENCE1
NAMEOFSEQUENCE2/SEQUENCE2
NAMEOFSEQUENCE3/SEQUENCE3
I done a struct:
typedef struct lane{
char *name;
char *sequence;
}lane;
and wrote this code:
int i=0;
lane* toSend = malloc(sizeof(*toSend)*3);
while (fgets(line,strlen(line),fileinput) != NULL){
//GETTING NAME AND SEQUENCE, LINE PER LINE
char *tempName = malloc(strlen(line)-strlen(strstr(line,"\\"))+1);
strncpy(tempName,line,strlen(line)-strlen(strstr(line,"\\")));
tempName[strlen(line)-strlen(strstr(line,"\\"))] = '\0';
char *tempSequence = malloc(strlen(strstr(line,"\\")));
strncpy(tempSequence,strstr(line,"\\")+1,strlen(strstr(line,"\\")));
tempSequence[strlen(strstr(line,"\\"))-1] = '\0';
//FILLING TOSEND
toSend[i].name = malloc(strlen(line)-strlen(strstr(line,"\\"))+1);
toSend[i].sequence = malloc(strlen(strstr(line,"\\")));
howmuchbyte += strlen(line)+1;
strcpy(toSend[i].name,tempName);
strcpy(toSend[i].sequence,tempSequence);
i++;
}
I put in "line" variable one line of the file at a time and put in tempName the NAMEOFSEQUENCEX of each sequence and put in tempSequence the SEQUENCEX.
At this point all is working. If i Print the "toSend" vector i get the right value!
So i wrote this:
MPI_Send(toSend, 3, MPI_BYTE, 1, tag, MPI_COMM_WORLD);
so i send from process with rank 0 to process with rank 1 (i have 2 process). I put 3 as count parameter because i have 3 elements in the array.
The process with rank 1 do this:
lane* received = malloc(sizeof(*received)*3);
MPI_Recv(received, 3, MPI_BYTE, 0, tag, MPI_COMM_WORLD, &status);
If i do this on process with rank 1:
printf("%s",received[0].name);
i get a segmentation fault. What do i wrong?

This could work if your strings are of fixed maximum length, e.g.
typedef struct lane{
char name[NAME_MAX];
char sequence[SEQ_MAX];
}lane;
In that case you can simply define a new MPI structured datatype and use it in both send and receive operations:
int blens[2] = { NAME_MAX, SEQ_MAX };
int disps[2] = { offsetof(lane, name), offsetof(lane, sequence) };
int oldtypes[2] = { MPI_CHAR, MPI_CHAR };
MPI_Datatype type_lane;
MPI_Type_create_struct(2, blens, disps, oldtypes, &type_lane);
MPI_Type_commit(&type_lane);
lane aLane[2];
if (rank == 0)
{
strncpy(aLane[0].name, NAME_MAX, "foo1");
strncpy(aLane[0].sequence, SEQ_MAX, "bar");
strncpy(aLane[1].name, NAME_MAX, "foo2");
strncpy(aLane[1].sequence, SEQ_MAX, "baz");
MPI_Send(aLane, 2, type_lane, 1, tag, MPI_COMM_WORLD);
}
else if (rank == 1)
{
MPI_Recv(aLane, 2, type_lane, 0, tag, MPI_COMM_WORLD, &status);
}
If your strings are of strongly varying lengths, then you should serialize each structure before sending it. The most simple thing that comes to my mind is to just concatenate all name/sequence pairs, separated by a NUL:
int total_length = 0;
for (i = 0; i < num_to_send; i++)
total_length += strlen(toSend[i].name) + strlen(toSend[i].sequence) + 2;
char *bigstr = malloc(total_length);
char *cur = bigstr;
for (i = 0; i < num_to_send; i++)
{
strcpy(cur, toSend[i].name);
cur += strlen(toSend[i].name) + 1;
strcpy(cur, toSend[i].sequence);
cur += strlen(toSend[i].sequence) + 1;
}
Now the content of bigstr is as follows:
toSend[0].name \0 toSend[0].sequence \0 toSend[1].name \0 toSend[1].sequence \0 ....
The sender can now send the string and dispose it:
MPI_Send(bigstr, total_length, MPI_CHAR, 1, tag, MPI_COMM_WORLD);
The receiver has to be prepared to receive a message of unknown size. That can be achieved by first calling MPI_Probe and then MPI_Recv:
MPI_Status;
MPI_Probe(1, tag, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_CHAR, &total_length);
char *bigstr = malloc(total_length);
MPI_Recv(bigstr, total_length, MPI_CHAR, 1, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
Now comes the part where you have to deserialise the big string into a collection of tuples. One way to do it is to first walk it and count the number of NULs and divide them by two. Then walk it again and copy each item to the corresponding location:
int num_structs = 0;
for (i = 0; i < total_length; i++)
if (bigstr[i] == '\0') num_structs++;
num_structs /= 2;
lane *lanes = malloc(num_structs * sizeof(lane));
char *cur = bigstr;
for (i = 0; i < num_structs; i++)
{
lanes[i].name = strdup(cur);
cur += strlen(cur);
lanes[i].sequence = strdup(cur);
cur += strlen(cur);
}
Another possible solution would be to utilise MPI_Pack and MPI_Unpack instead.

You can't just send raw pointers across an MPI channel. Well, you can, but the process that receives a pointer from some other process won't have the same data at the memory location (in their own memory space) referred to by the pointer.
If you want to send a variably-sized array (such as a string) through MPI, you'll need to test for the size of the array first, and allocate an appropriately sized array on the receiving end.
For more info: How to send and receive string using MPI

Related

MPI C - Root node receives more than one arrays

Each slave will send an array num with length len to root node. How will I be able to store all these array in 2D array?
if (world_rank == root) {
for(i=1; i<world_size;i++) {
// clueless what to do
}
MPI_Waitall(world_size-1, &rcv_request[1], &status[1]);
}
else {
MPI_Isend(num, len, MPI_FLOAT, i, 1, MPI_COMM_WORLD, &send_request[i]);
MPI_Wait(&send_request[1], &status[1]);
}

C-MPI Send created typedef struct with array of chars

Hello I have a file containing that kind of data lines:
AsfAGHM5om 00000000000000000000000000000000 0000222200002222000022220000222200002222000000001111
I want to read this kind of data and send them over using C and MPI. So I've reached the following C code:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str{
char *key;
char *index;
char *value;
} tuple;
int main(int argc, char** argv) {
// Initialize the MPI environment
MPI_Init(&argc, &argv);
// Initialize file pointer
FILE *fp = fopen("tuples","r");
// define original structure that stores file and temp used by each process
tuple A[10000],B[10000];
// mpi structure name
MPI_Datatype mpi_tuples_str;
// number of structure members
const int nitems = 3;
// array of structure member sizes
int blocklengths[3];
blocklengths[0] = sizeof(A->key);
blocklengths[1] = sizeof(A->index);
blocklengths[2] = sizeof(A->value);
// structure member types
MPI_Datatype types[3] = {MPI_CHAR,MPI_CHAR,MPI_CHAR};
// status
MPI_Status status;
// offset of structure members
MPI_Aint offsets[3];
offsets[0] = offsetof(tuple,key);
offsets[1] = offsetof(tuple,index);
offsets[2] = offsetof(tuple,value);
// create mpi struct
MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
MPI_Type_commit(&mpi_tuples_str);
// Get the number of processes
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Get the rank of the process
int my_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
int index = 0;
int i;
int local_A_size = (10000%size == 0) ? 10000/size : 0;
if ( my_rank == 0){
char text[10000];
char *p;
p=strtok(NULL," ");
// node0 reads file form hard drive and saves file to struct
while( fgets(text,10000,fp)!=NULL){
p = strtok (text," ");
char *temp[3];
temp[0]=p;
A[index].key=temp[0];
p = strtok (NULL, " ");
temp[1] = p;
A[index].index=temp[1];
p = strtok (NULL, " ");
temp[2] = p;
A[index].value=temp[2];
// printf("%s ",A[index].key);
// printf("%s ",A[index].index);
// printf("%s\n",A[index].value);
index++;
}
fclose(fp);
}
if ( local_A_size != 0){
if (my_rank == 0) {
printf("File saved to memory of process %d!\n",my_rank);
printf("Process %d sending struct data to others...\n",my_rank);
}
// send struct to all processes
MPI_Scatter(&A,local_A_size,mpi_tuples_str,B,local_A_size,mpi_tuples_str,0,MPI_COMM_WORLD);
// MPI_Bcast(&A,index,mpi_tuples_str,0,MPI_COMM_WORLD);
for(i=0;i<=local_A_size;i++)
printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);
if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);
}
else
{
if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);
}
// free memory used by mpi_tuples_str
MPI_Type_free(&mpi_tuples_str);
// Finalize
MPI_Finalize();
return 0;
}
So the problem here is, as far as I can understand_ the creation and allocation of memory of my struct at first and the packing and sending of it at second.
As you can see I've tried both MPI_Scatter & MPI_Bcast but none of them helped me.
The result is that, as it supposed to, process 0 that reads the file has data but all others not. Also I'm getting this weird message of
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= EXIT CODE: 11
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
I'll be so grateful if someone can enlighten me!!
Alright I 've changed my code to the following:
`#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str{
char key[10];
char index[12];
char value[52];
} tuple;
int main(int argc, char** argv) {
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Initialize file pointer
FILE *fp = fopen("tuples_mini","r");
// define original structure that stores file and temp used by each process
tuple A[10000],B[10000];
// mpi structure name
MPI_Datatype mpi_tuples_str;
// number of structure members
const int nitems = 3;
// array of structure member sizes
int blocklengths[3];
blocklengths[0] = sizeof(10);
blocklengths[1] = sizeof(12);
blocklengths[2] = sizeof(52);
// structure member types
MPI_Datatype types[3] = {MPI_CHAR,MPI_CHAR,MPI_CHAR};
// status
MPI_Status status;
// offset of structure members
MPI_Aint offsets[3];
offsets[0] = offsetof(tuple,key);
offsets[1] = offsetof(tuple,index);
offsets[2] = offsetof(tuple,value);
// create mpi struct
MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
MPI_Type_commit(&mpi_tuples_str);
// Get the number of processes
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Get the rank of the process
int my_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
int index = 0;
int i;
int local_A_size = (10000%size == 0) ? 10000/size : 0;
char *tmp[10000],*b[10000];
if ( my_rank == 0){
char text[10000];
char *p;
p=strtok(NULL," ");
// node0 reads file form hard drive and saves file to struct
while( fgets(text,10000,fp)!=NULL){
p = strtok (text," ");
char *temp[3];
temp[0]=p;
strcpy(A[index].key,temp[0]);
p = strtok (NULL, " ");
temp[1] = p;
strcpy(A[index].index,temp[1]);
p = strtok (NULL, " ");
temp[2] = p;
strcpy(A[index].value,temp[2]);
printf("%s ",A[index].key);
printf("%s ",A[index].index);
printf("%s\n",A[index].value);
index++;
}
fclose(fp);
}
if ( local_A_size != 0){
if (my_rank == 0) {
printf("File saved to memory of process %d!\n",my_rank);
printf("Process %d sending struct data to others...\n",my_rank);
}
// send struct to all processes
MPI_Scatter(&A,index,mpi_tuples_str,B,index,mpi_tuples_str,0,MPI_COMM_WORLD);
// MPI_Bcast(&tmp,index,MPI_CHAR,0,MPI_COMM_WORLD);
for(i=0;i<=local_A_size;i++){
// MPI_Recv(&tmp,index,MPI_CHAR,0,10,MPI_COMM_WORLD,&status);
printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);
}
if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);
}
else
{
if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);
}
// free memory used by mpi_tuples_str
MPI_Type_free(&mpi_tuples_str);
// Finalize
MPI_Finalize();
return 0;
}`
but that lead me to new error:
============================================================================== =====
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= EXIT CODE: 6
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
============================================================================== =====
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Aborted (signal 6)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions
after last suggestions!
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str{
char key[10];
char index[12];
char value[52];
} tuple;
int main(int argc, char** argv) {
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Initialize file pointer
FILE *fp = fopen("tuples_mini","r");
// define original structure that stores file and temp used by each process
tuple A[10000],B[10000];
// mpi structure name
MPI_Datatype mpi_tuples_str;
// number of structure members
const int nitems = 3;
// array of structure member sizes
int blocklengths[3];
blocklengths[0] = 11;
blocklengths[1] = 33;
blocklengths[2] = 53;
// structure member types
MPI_Datatype types[3] = {MPI_CHAR,MPI_CHAR,MPI_CHAR};
// status
MPI_Status status;
// offset of structure members
MPI_Aint offsets[3];
offsets[0] = offsetof(tuple,key);
offsets[1] = offsetof(tuple,index);
offsets[2] = offsetof(tuple,value);
// create mpi struct
MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
MPI_Type_commit(&mpi_tuples_str);
// Get the number of processes
int size;
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Get the rank of the process
int my_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
int index = 0;
int i;
int local_A_size = (10000%size == 0) ? 10000/size : 0;
char *tmp[10000],*b[10000];
if ( my_rank == 0){
char text[10000];
char *p;
// p=strtok(NULL," ");
// node0 reads file form hard drive and saves file to struct
while( fgets(text,10000,fp) != NULL && fp != NULL){
p = strtok (text," ");
char *temp[3];
temp[0]=p;
strcpy(A[index].key,temp[0]);
p = strtok (NULL, " ");
temp[1] = p;
strcpy(A[index].index,temp[1]);
p = strtok (NULL, " ");
temp[2] = p;
strcpy(A[index].value,temp[2]);
printf("%s ",A[index].key);
printf("%s ",A[index].index);
printf("%s\n",A[index].value);
tmp[index] = temp[0];
// printf("%s\n",tmp[index]);
index++;
}
fclose(fp);
}
if ( local_A_size != 0){
if (my_rank == 0) {
printf("File saved to memory of process %d!\n",my_rank);
printf("Process %d sending struct data to others...\n",my_rank);
// MPI_Send(&A,index,mpi_tuples_str,0,10,MPI_COMM_WORLD);
}
// send struct to all processes
MPI_Scatter(&A,index,mpi_tuples_str,B,index,mpi_tuples_str,0,MPI_COMM_WORLD);
// MPI_Bcast(&tmp,index,MPI_CHAR,0,MPI_COMM_WORLD);
// MPI_Bcast(&A,index,mpi_tuples_str,0,MPI_COMM_WORLD);
for(i=0;i<=local_A_size;i++){
// MPI_Recv(&tmp,index,MPI_CHAR,0,10,MPI_COMM_WORLD,&status);
// MPI_Recv(&A,index,mpi_tuples_str,0,10,MPI_COMM_WORLD,&status);
printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);
}
if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);
}
else
{
if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);
}
// free memory used by mpi_tuples_str
MPI_Type_free(&mpi_tuples_str);
// Finalize
MPI_Finalize();
return 0;
}
I applied all the comments about problems in the posted code, this is the result:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str
{
char key[11];
char index[33];
char value[53];
} tuple;
int main( void )
{
// Initialize the MPI environment
MPI_Init( NULL, NULL );
// Initialize file pointer
FILE *fp = NULL;
if( NULL == ( fp = fopen( "tuples_mini" ,"r" ) ) )
{
perror( "fopen for read of truples_mini failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
// define original structure that stores file and temp used by each process
tuple A[10000];
tuple B[10000];
// mpi structure name
MPI_Datatype mpi_tuples_str;
// number of structure members
const int nitems = 3;
// array of structure member sizes
int blocklengths[3];
blocklengths[0] = 11;
blocklengths[1] = 33;
blocklengths[2] = 53;
// structure member types
MPI_Datatype types[3] = { MPI_CHAR, MPI_CHAR, MPI_CHAR };
// status
//MPI_Status status;
// offset of structure members
MPI_Aint offsets[3];
offsets[0] = offsetof( tuple,key);
offsets[1] = offsetof( tuple,index);
offsets[2] = offsetof( tuple,value);
// create mpi struct
MPI_Type_create_struct( nitems, blocklengths, offsets, types, &mpi_tuples_str);
MPI_Type_commit( &mpi_tuples_str);
// Get the number of processes
int size;
MPI_Comm_size( MPI_COMM_WORLD, &size);
// Get the rank of the process
int my_rank;
MPI_Comm_rank( MPI_COMM_WORLD, &my_rank);
int index = 0;
int i;
int local_A_size = (10000%size == 0) ? 10000/size : 0;
//char *tmp[10000];
//char *b[10000];
if ( my_rank == 0)
{
char text[10000];
char *p;
//p=strtok(NULL," ");
// node0 reads file from hard drive and saves file to struct
while( fgets( text, sizeof text, fp ) )
{
p = strtok (text," ");
char *temp[3];
temp[0]=p;
strcpy( A[index].key,temp[0]);
p = strtok (NULL, " ");
temp[1] = p;
strcpy( A[index].index,temp[1]);
p = strtok (NULL, " ");
temp[2] = p;
strcpy( A[index].value,temp[2]);
printf( "%s ",A[index].key);
printf( "%s ",A[index].index);
printf( "%s\n",A[index].value);
index++;
}
fclose(fp);
}
if ( local_A_size != 0)
{
if (my_rank == 0)
{
printf( "File saved to memory of process %d!\n",my_rank);
printf( "Process %d sending struct data to others...\n",my_rank);
}
// send struct to all processes
MPI_Scatter( &A,index, mpi_tuples_str, B, index, mpi_tuples_str, 0, MPI_COMM_WORLD;
// MPI_Bcast( &tmp,index, MPI_CHAR, 0, MPI_COMM_WORLD);
for(i=0;i<=local_A_size;i++)
{
// MPI_Recv( &tmp, index, MPI_CHAR, 0, 10, MPI_COMM_WORLD, &status);
printf( "I'm process %d and my result is: %s\n", my_rank, B[i].key);
}
if (my_rank == 0)
printf("Data sent from process %d to others...\n", my_rank);
}
else
{
if (my_rank == 0)
printf( "Number of processes must be an exact divisor of %d, %d in not %ds divisor\n", index, size,index);
}
// free memory used by mpi_tuples_str
MPI_Type_free( &mpi_tuples_str);
// Finalize
MPI_Finalize();
return 0;
}
I setup the tuples_mini file to contain:
AsfAGHM5om 00000000000000000000000000000000 0000222200002222000022220000222200002222000000001111
when I ran the program on my ubuntu linux 14.04 with 4 core processor, this is the output:
AsfAGHM5om 00000000000000000000000000000000 0000222200002222000022220000222200002222000000001111
File saved to memory of process 0!
Process 0 sending struct data to others...
I'm process 0 and my result is: AsfAGHM5om
I'm process 0 and my result is:
then several dozens of this line:
I'm process 0 and my result is:
followed by these lines:
I'm process 0 and my result is:
I'm process 0 and my result is: AsfAGHM5om
Data sent from process 0 to others...
so there seems to be a logic problem in the code, but it does not seg fault
on the second version of the posted code
The most likely cause of the signal 6/sigabort is because the first call to strtok() has NULL as the first parameter rather than the address of a visible buffer.
IMO: that first call to strtok() should be completely removed from the program.

Create MPI type for struct containing dynamic array

I'm trying to send a struct which has one of the member as a dynamic array, but this array doesn't seem to be sent properly. Any suggestion on how to do this?
This is what I have:
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType(MPI_Datatype* newType, int cLen, struct bar* msg)
{
int blockLengths[3] = {1, 1, cLen};
MPI_Datatype types[3] = {MPI_INT, MPI_INT, MPI_INT};
MPI_Aint offsets[3];
MPI_Aint addrB, addrC;
MPI_Address(&(msg->b), &addrB);
MPI_Address(msg->c, &addrC);
offsets[0] = offsetof(struct bar, a);
offsets[1] = offsetof(struct bar, b);
offsets[2] = addrC - addrB;
MPI_Type_create_struct(3, blockLengths, offsets, types, newType);
MPI_Type_commit(newType);
}
void main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
int cLen = argv[0];
MPI_Datatype MPI_BAR_TYPE;
struct bar* msg = malloc(sizeof(*msg));
msg->c = malloc(sizeof(int) * cLen);
defineMPIType(&MPI_BAR_TYPE, cLen, msg);
if (rank == 0)
{
msg->a = 1;
msg->b = 2;
for (int i = 0; i < cLen; ++i)
msg->c[i] = i;
MPI_Send(msg, 1, MPI_BAR_TYPE, 1, 111, MPI_COMM_WORLD);
}
else
{
MPI_Status stat;
MPI_Recv(msg, 1, MPI_BAR_TYPE, 0, 111, MPI_COMM_WORLD, &stat);
}
printf("Rank %d has c = [", rank);
for (int i = 0; i < cLen; ++i)
printf("%d, ", msg->c[i]);
printf("]\n");
free(msg);
MPI_Type_free(&MPI_BAR_TYPE);
MPI_Finalize();
}
Members a and b got sent properly, but c didn't.
There are a few issues in your code, even ignoring the issue of the type itself:
The first one is that you allocated memory for your c array only on process #0, then you (tried to) send this data to process #1. But process #1 didn't allocate any memory for storing the message. So even if the way the sending is done was correct, the code would have failed.
Names starting with MPI_ are reserved for the MPI library so you cannot use them as you wish. You have to find another name for your MPI_BAR_TYPE.
This line puzzles me somewhat: int cLen = argv[0]; I imagine you want to read from the command line the size of the array to allocate, in which case maybe that should read something like int clen = atoi(argv[1]); (forgetting about test for validity of this which would need to be properly handled...)
You only test if the process is of rank #0 or not, meaning that if for some reason you launched 3 processes, the process of rank #2 will wait forever for a message from process of rank #0 that will never arrive.
And finally the array itself: in your code there is a big confusion between the pointer c and the data pointed to by c. Your structure embeds the pointer, but not the memory pointed to. So you cannot map into an MPI structure the corresponding data... The most obvious reason is that from one call to the next (or from one process to the next), there is no guaranty that the offset from the address of the structure and the address of the data pointed to by c will be identical (and indeed, it is almost guaranteed it will be different). So you cannot reliably map them.
What you need to do for solving your problem is therefore to only transfer your 2 integers a and b in one go (possibly creating a MPI structure for transferring arrays of them if needed). Then you will transfer the memory pointed by c, which you would have allocated beforehand.
Your code could become for example:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType( MPI_Datatype* newType ) {
struct bar tmp[2];
MPI_Aint extent = &tmp[1] - &tmp[0];
MPI_Type_create_resized( MPI_2INT, 0, extent, newType );
MPI_Type_commit( newType );
}
int main( int argc, char* argv[] ) {
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &p );
int cLen = atoi( argv[1] );
MPI_Datatype Bar_type;
defineMPIType( &Bar_type );
struct bar msg;
msg.c = ( int* ) malloc( sizeof( int ) * cLen );
if ( rank == 0 ) {
msg.a = 1;
msg.b = 2;
for ( int i = 0; i < cLen; ++i ) {
msg.c[i] = i;
}
MPI_Send( &msg, 1, Bar_type, 1, 111, MPI_COMM_WORLD );
MPI_Send( msg.c, cLen, MPI_INT, 1, 222, MPI_COMM_WORLD );
}
else if ( rank == 1 ) {
MPI_Recv( &msg, 1, Bar_type, 0, 111, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
MPI_Recv( msg.c, cLen, MPI_INT, 0, 222, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
}
printf("Rank %d has a = %d, b = %d, c = [", rank, msg.a, msg.b );
for ( int i = 0; i < cLen - 1; ++i ) {
printf( "%d, ", msg.c[i] );
}
printf( "%d]\n", msg.c[cLen - 1] );
free( msg.c );
MPI_Type_free( &Bar_type );
MPI_Finalize();
return 0;
}
Which gives:
$ mpirun -n 2 ./a.out 3
Rank 0 has a = 1, b = 2, c = [0, 1, 2]
Rank 1 has a = 1, b = 2, c = [0, 1, 2]
Happy MPI coding.

File read issues - Parallel version of Game of Life

For my Parallel Computing class, I am working on a project that parallelizes the Game of Life using MPI. I am specifically implementing exercise 6.13 in "Parallel Programming in C with MPI and OpenMP" by Michael J. Quinn.
I am using the author's pre-written library function, "read_row_striped_matrix". The following is the code for the function:
/*
* Process p-1 opens a file and inputs a two-dimensional
* matrix, reading and distributing blocks of rows to the
* other processes.
*/
void read_row_striped_matrix (
char *s, /* IN - File name */
void ***subs, /* OUT - 2D submatrix indices */
void **storage, /* OUT - Submatrix stored here */
MPI_Datatype dtype, /* IN - Matrix element type */
int *m, /* OUT - Matrix rows */
int *n, /* OUT - Matrix cols */
MPI_Comm comm) /* IN - Communicator */
{
int datum_size; /* Size of matrix element */
int i;
int id; /* Process rank */
FILE *infileptr; /* Input file pointer */
int local_rows; /* Rows on this proc */
void **lptr; /* Pointer into 'subs' */
int p; /* Number of processes */
void *rptr; /* Pointer into 'storage' */
MPI_Status status; /* Result of receive */
int x; /* Result of read */
MPI_Comm_size (comm, &p);
MPI_Comm_rank (comm, &id);
datum_size = get_size (dtype);
/* Process p-1 opens file, reads size of matrix,
and broadcasts matrix dimensions to other procs */
if (id == (p-1)) {
infileptr = fopen (s, "r");
if (infileptr == NULL) *m = 0;
else {
fread (m, sizeof(int), 1, infileptr);
fread (n, sizeof(int), 1, infileptr);
}
}
MPI_Bcast (m, 1, MPI_INT, p-1, comm);
if (!(*m)) MPI_Abort (MPI_COMM_WORLD, OPEN_FILE_ERROR);
MPI_Bcast (n, 1, MPI_INT, p-1, comm);
local_rows = BLOCK_SIZE(id,p,*m);
/* Dynamically allocate matrix. Allow double subscripting
through 'a'. */
*storage = (void *) my_malloc (id,
local_rows * *n * datum_size);
*subs = (void **) my_malloc (id, local_rows * PTR_SIZE);
lptr = (void *) &(*subs[0]);
rptr = (void *) *storage;
for (i = 0; i < local_rows; i++) {
*(lptr++)= (void *) rptr;
rptr += *n * datum_size;
}
/* Process p-1 reads blocks of rows from file and
sends each block to the correct destination process.
The last block it keeps. */
if (id == (p-1)) {
for (i = 0; i < p-1; i++) {
x = fread (*storage, datum_size,
BLOCK_SIZE(i,p,*m) * *n, infileptr);
MPI_Send (*storage, BLOCK_SIZE(i,p,*m) * *n, dtype,
i, DATA_MSG, comm);
}
x = fread (*storage, datum_size, local_rows * *n,
infileptr);
fclose (infileptr);
} else
MPI_Recv (*storage, local_rows * *n, dtype, p-1,
DATA_MSG, comm, &status);
}
In the beginning of my code, I call "read_row_striped_matrix" like this:
#include <stdio.h>
#include <mpi.h>
#include "MyMPI.h"
typedef int dtype;
#define MPI_TYPE MPI_INT
int main(int argc, char *argv[]) {
dtype** matrix; /* Doubly-subscripted array */
dtype* storage; /* Local portion of array elements */
int proc_id; /* Process Rank */
int row_count; /* Number of rows in matrix */
int col_count; /* Number of columns in matrix */
int proc_count; /* Number of processes */
int i; /* Used with for loop */
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &proc_id);
MPI_Comm_size (MPI_COMM_WORLD, &proc_count);
read_row_striped_matrix (argv[3], (void *) &matrix, (void *) &storage, MPI_TYPE,
&row_count, &col_count, MPI_COMM_WORLD);
....
The problem is, my implementation was getting stuck in an infinite loop. So I started debugging by testing to see if the data was being read from the text file correctly. My text file named "file_input.txt" contains the following input, where the first number (5) represents the number of rows, and the second number (also 5) represents the number of cols, and the rest of the data are the values in the matrix:
5 5 0 0 1 0 1 0 0 1 ...
I inserted the following printf statements in the section of library code where the length and height was being read from the text file:
if (id == (p-1))
printf("The name of the file is %s\n", s);
infileptr = fopen (s, "r");
if (infileptr == NULL) *m = 0;
else {
printf("The value of m is %d\n", *m);
size_t ret_val = fread (m, sizeof(int), 1, infileptr);
size_t next_ret_val = fread (n, sizeof(int), 1, infileptr);
printf("The total # of elements successfully read is: %d\n", ret_val);
printf("The total # of elements successfully read is: %d\n", next_ret_val);
printf("The value of m is %d\n", *m);
printf("The value of n is %d\n", *n);
}
}
For executing "project_3 5 5 file_input.txt", The output of the program is:
The name of the file is: file_input.txt
The value of m is 0
The total number of elements successfully read is: 1
The total number of elements successfully read is: 1
The value of m is: 540549176
The value of n is: 540090416
...
From what I observe, the name of the file was read in correctly, and the value of m (0) is correct before calling fread. fread is reading in the correct # of elements for both m and n, but the values are "540549176" and "540090416" instead of 5 and 5. When I try changing the numbers in the beginning of the text file to say, "3 and 4" for example, the value of m and n does not change.
Does anybody have any idea why the first two integers are not being read in from the text file correctly? Thanks in advance.
You have two options here:
this program is expecting binary input. so you need to produce binary input somehow. "5" is an ascii character with the hex value 0x35 (decimal 53). When you fread sizeof(int), you are actually going to pull in 2 characters.
you can edit the program to parse ascii text but this is kind of annoying. First you read in a line of the file, then you tokenize it, then you convert each token into integers. Are you coming from a perl/python background? This text conversion stuff is nearly automatic in scripting languages. nothing is automatic in C
Look you need to rip the library function off and rewrite it to read and interpret text files. At present it reads binary data, when it reads into m and n it reads sizeof(int) (probably 4 bytes) of hexadecimal data ie 00,00,00,05 is what's expected to be in your file but the first 4 bytes are something like 76,32,76,32
Rather than rewrite the library function it probably makes sense to write a file compiler that reads a text file as input and writes it as it's binary data

MPI - send my own structure while using MPI_Probe()

I need to send my own structure with MPI_Send(). The problem is, I am not sure how to use structures in MPI properly. Of course I've tried to find it by myself, but I haven't found any example which suits exactly my needs.
Now, when I run Makefile, I got this error:
probe_and_struct.c: In function ‘main’:
probe_and_struct.c:72:13: error: expected ‘;’ before ‘buf’
myStruct buf;
^
probe_and_struct.c:73:4: error: ‘buf’ undeclared (first use in this function)
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
^
probe_and_struct.c:73:4: note: each undeclared identifier is reported only once for each function it appears in
probe_and_struct.c:73:21: error: expected expression before ‘)’ token
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
^
make: *** [probe_and_struct] Error 1
So, could you please tell me, what am I doing wrong and how should I use the structure correctly?
EDIT:
I've rewritten the code, but now the program crashes with Segmentation fault - on MPI_Send().
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define ARR_LEN 2 // length of test array and the size sent
int main() {
//---------------------------------------------------------------------------------------------------------------------------------------
// Create own structure
//----------------------
// Structure of structure :-)
struct {
int id;
char c;
} value;
// Declare parts of structure
MPI_Datatype myStruct;
int blockLengths[2];
MPI_Aint indices[2];
MPI_Datatype types[2];
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
//---------------------------------------------------------------------------------------------------------------------------------------
// Message passing
//-----------------
MPI_Init(NULL, NULL);
value.id = 0;
value.c = 'a';
// Number of processes, ID of current process
int world_size;
MPI_Comm_size( MPI_COMM_WORLD, &world_size );
int world_rank;
MPI_Comm_rank( MPI_COMM_WORLD, &world_rank );
// Test array to send
int arr[ 2 ] = {10,20};
MPI_Status status;
switch( world_rank ) {
case 0:
printf("This is the process number %d.\n\t", world_rank);
MPI_Send( &value, 2, myStruct, 1, 0, MPI_COMM_WORLD);
printf("The array of INT was sent.\n");
break;
case 1:
// Recognize the size of the message
MPI_Probe( 0, 0, MPI_COMM_WORLD, &status );
// Number of blocks sent
int status_size;
MPI_Get_count( &status, myStruct, &status_size );
// Allocate buffer with the size needed
myStruct buf;
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
// Receive and print message
MPI_Recv( buf, status_size, myStruct, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
printf("This is the process number %d.\n\t[ ", world_rank);
for( int i = 0; i < status_size; i++ ) {
printf( "%d ", buf[i] );
}
printf("]\n");
break;
default:
printf("This is the process number %d.\n", world_rank);
break;
}
MPI_Type_free( &myStruct );
MPI_Finalize();
return 0;
}
Makefile:
CC=mpicc
STD=-std=c11
all: probe_and_struct
probe_and_struct: probe_and_struct.c
$(CC) -o probe_and_struct probe_and_struct.c $(STD)
clean:
rm -f probe_and_struct
My code - 2nd version:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define ARR_LEN 2 // length of test array and the size sent
int main()
{
MPI_Init(NULL, NULL);
//---------------------------------------------------------------------------------------------------------------------------------------
// Create own structure
//----------------------
// Structure of structure :-)
typedef struct Values
{
int id;
char c;
} Values;
Values value;
// Declare parts of structure
MPI_Datatype myStruct;
int blockLengths[2];
MPI_Aint indices[2];
MPI_Datatype types[2];
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
//---------------------------------------------------------------------------------------------------------------------------------------
// Message passing
//-----------------
value.id = 0;
value.c = 'a';
// Number of processes, ID of current process
int world_size;
MPI_Comm_size( MPI_COMM_WORLD, &world_size );
int world_rank;
MPI_Comm_rank( MPI_COMM_WORLD, &world_rank );
// Test array to send
//int arr[ 2 ] = {10,20};
MPI_Status status;
switch( world_rank ) {
case 0:
printf("Toto je proces cislo %d.\n\t", world_rank);
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
printf("Odeslano pole INTu.\n");
break;
case 1:
// Recognize the size of the message
MPI_Probe( 0, 0, MPI_COMM_WORLD, &status );
// Number of blocks sent
int status_size;
MPI_Get_count( &status, myStruct, &status_size );
puts("b");
// Allocate buffer with the size needed
Values * buf;
buf = (Values *) malloc( sizeof(Values) * status_size );
puts("b");
// Receive and print message
//MPI_Recv( buf, status_size, myStruct, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
printf("Toto je proces cislo %d.\n\t[ ", world_rank);
for( int i = 0; i < status_size; i++ ) {
printf( "%d %c", buf[i].id, buf[i].c );
}
printf("]\n");
break;
default:
printf("Toto je proces cislo %d.\n", world_rank);
break;
}
MPI_Type_free( &myStruct );
MPI_Finalize();
return 0;
}
You're using myStruct like a type and trying to instantiate buf, but myStruct is an instance of MPI_Datatype (and not a type).
This part of your code (where myStruct is declared as an MPI_Datatype):
// Declare parts of structure
MPI_Datatype myStruct;
conflicts with this part (where you're trying to use myStruct as a type):
// Allocate buffer with the size needed
myStruct buf;
buf = (myStruct *) malloc( sizeof(myStruct) * status_size );
You are not constructing your MPI datatype correctly. Or rather, you are not using correctly the constructed datatype whiel sending the structure. You should do either of the following:
1. Fix the offsets inside the datatype
This code:
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
...
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
should become:
// Initialize parts of structure
blockLengths[0] = 1; // stucture's attributes' sizes
blockLengths[1] = 1;
types[0] = MPI_INT; // structure's attributes' data types
types[1] = MPI_CHAR;
MPI_Address( &value.id, &indices[0] );
MPI_Address( &value.c, &indices[1] );
// Convert the absolute addresses into offsets
indices[1] -= indices[0];
indices[0] = 0;
// Create and commit new structure
MPI_Type_struct( 2, blockLengths, indices, types, &myStruct );
MPI_Type_commit( &myStruct );
...
MPI_Send( &value, 1, myStruct, 1, 0, MPI_COMM_WORLD);
Also, if you are willing to send an array of such datatype, you should take some special measures to account for the type padding done by the compiler. See in this question how.
2. Use MPI_BOTTOM while sending the data
Instead of fixing up the offsets in the type description, you could keep the absolute addresses. The downside is that with absolute addresses you can only send the content of that specific variable used while constructing the datatype (since other variables usually end up somewhere else in memory). When using such datatypes, one does not specify the address of a buffer but MPI_BOTTOM, i.e. this code:
MPI_Send( &value, sizeof(struct Values), myStruct, 1, 0, MPI_COMM_WORLD);
becomes:
MPI_Send( MPI_BOTTOM, 1, myStruct, 1, 0, MPI_COMM_WORLD);
Note that in this case the number of elements to send must be equal to 1, i.e. it is not possible to send arrays (unless the datatype itself describes all the elements of an array).
Note also that in both cases sizeof(struct Values) is wrong and has to be corrected to 1 since the second argument of MPI_Send gives the number of elements to be sent and the actual data size of each element is already encoded in the MPI datatype.
I would strongly recommend that you go with option #1.
You are confusing the MPI_type with the type of the variable. For example, let's use a simple int. The MPI_type of an int is MPI_INT, right? But this is not proper code:
MPI_INT a = 5; //wrong, MPI_INT is an MPI_Type
//not the type we want to declare a variable
MPI_Send(&a, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
Instead, you would use:
int a = 5; //int is used to declare a variable
MPI_Send(&a, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); //MPI_INT is the type to
//send the variable
Similarly, if you have a struct as:
struct value {
int id;
char c;
};
Then, after you have used MPI_Type_commit to declare a new MPI type, you would use:
struct value a = {4, 'b'}; //struct value is used to declare the variable
MPI_Send(&a, 1, myStruct, 1, 0, MPI_COMM_WORLD); //myStruct is the MPI_Type used to
//send the variable

Resources