MPI - send my own structure while using MPI_Probe() - c

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

Related

Correct method of MPI send/recv on an array of structs

I've been setting up a four-node mpi cluster with raspberry pis. As far as I can tell, I am down to one final major issue, and that is how to send an array of structs from each worker to the manager. I have cropped down the code to the below, but this could take a few tries, as I might have cropped too much. Albeit, I still get the same error (a seg fault, saying an address is not mapped), but sorry if there's a bit of back and fourth.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
struct ticknrank
{
char * ticker;
int errors;
int rank;
};
int main() //Designed for one master, three slaves
{
// i am under the impression the problem lies somewhere in this beginning section, before the commit.
int my_id;
MPI_Init(NULL,NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Status status;
MPI_Datatype types[3] = {MPI_CHAR,MPI_INT,MPI_INT};
MPI_Datatype MPI_ticknrank, MPI_tmp;
int blocklengths[3] ={8,1,1};
MPI_Aint offsets[3];
offsets[0] = offsetof(struct ticknrank,ticker);
offsets[1] = offsetof(struct ticknrank,errors);
offsets[2]= offsetof(struct ticknrank,rank);
MPI_Aint lb, extent;
MPI_Type_create_struct(3,blocklengths, offsets, types, &MPI_tmp);
MPI_Type_get_extent(MPI_tmp, &lb, &extent);
MPI_Type_create_resized(MPI_tmp, lb, extent, &MPI_ticknrank);
MPI_Type_commit(&MPI_ticknrank);
// NOTE: sizeof(ticknrank) = 12, while MPI_Type_size(ticknrank) = 16. Not sure what to do about that.
if(my_id == 0) // meaning this process is a host job
{
//NOTE: NodethrRes and fou can be ommitted, I was just lazy and didn't wanna delete them
//on my cluster.
int length = 2;
struct ticknrank * NodeTwoRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
struct ticknrank * NodeThrRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
struct ticknrank * NodeFouRes = (struct ticknrank *)malloc(length * sizeof(struct ticknrank));
MPI_Recv(NodeTwoRes, length, MPI_ticknrank,1,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
MPI_Recv(NodeThrRes, length, MPI_ticknrank,2,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
MPI_Recv(NodeFouRes, length, MPI_ticknrank,3,MPI_ANY_TAG, MPI_COMM_WORLD, &status);
printf("%s\n", NodeTwoRes[0].ticker);
}
else
{
int myLen = 2;
struct ticknrank * results = malloc(myLen * sizeof(struct ticknrank));
results[0].ticker = strdup("FIRST");
results[0].rank = 4;
results[0].errors = 7;
results[1].ticker = strdup("SECON");
results[1].rank = 3;
results[1].errors = 15;
MPI_Send(results,myLen,MPI_ticknrank,0,1,MPI_COMM_WORLD);
}
MPI_Type_free(&MPI_ticknrank);
MPI_Finalize();
return 0;
}
The C struct is a char * ticker (which is 4 bytes if you are running 32 bits), but the derived datatype is for a char ticker[8] which is indeed 8 bytes.
If you want to send multiple struct ticknrank in one shot, then the data should be in contiguous memory, which means moving from char * ticker to char ticker[8], and replacing strdup() with strcpy() (and up to you to make sure there is no buffer overflow).

Create and communicate an "array of structs" using MPI Derived datatypes

I am trying to program an MPI_Alltoallv using an MPI Derived datatype using MPI_Type_create_struct. I could not find any examples solving this particular problem. Most examples like this perform communication(Send/Recv) using a single struct member, whereas I am targeting an array of structs. Following is a simpler test code that attempts a MPI_Sendrecv operation on an array of structs created using DDT:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <stddef.h>
typedef struct sample{
char str[12];
int count;
}my_struct;
int main(int argc, char **argv)
{
int rank, count;
my_struct *sbuf = (my_struct *) calloc (sizeof(my_struct),5);
my_struct *rbuf = (my_struct *) calloc (sizeof(my_struct),5);
int blens[2];
MPI_Aint displs[2];
MPI_Aint baseaddr, addr1, addr2;
MPI_Datatype types[2];
MPI_Datatype contigs[5];
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
strcpy(sbuf[0].str,"ACTGCCAATTCG");
sbuf[0].count = 10;
strcpy(sbuf[1].str,"ACTGCCCATACG");
sbuf[1].count = 5;
strcpy(sbuf[2].str,"ACTGCCAATTTT");
sbuf[2].count = 6;
strcpy(sbuf[3].str,"CCTCCCAATTCG");
sbuf[3].count = 12;
strcpy(sbuf[4].str,"ACTATGAATTCG");
sbuf[4].count = 8;
blens[0] = 12; blens[1] = 1;
types[0] = MPI_CHAR; types[1] = MPI_INT;
for (int i=0; i<5; i++)
{
MPI_Get_address ( &sbuf[i], &baseaddr);
MPI_Get_address ( &sbuf[i].str, &addr1);
MPI_Get_address ( &sbuf[i].count, &addr2);
displs[0] = addr1 - baseaddr;
displs[1] = addr2 - baseaddr;
MPI_Type_create_struct(2, blens, displs, types, &contigs[i]);
MPI_Type_commit(&contigs[i]);
}
/* send to ourself */
MPI_Sendrecv(sbuf, 5, contigs, 0, 0,
rbuf, 5, contigs, 0, 0,
MPI_COMM_SELF, &status);
for (int i=0; i<5; i++)
MPI_Type_free(&contigs[i]);
MPI_Finalize();
return 0;
}
I get the following warning at compile time:
coll.c(53): warning #810: conversion from "MPI_Datatype={int} *" to "MPI_Datatype={int}" may lose significant bits
MPI_Sendrecv(sbuf, 5, contigs, 0, 0,
^
coll.c(54): warning #810: conversion from "MPI_Datatype={int} *" to "MPI_Datatype={int}" may lose significant bits
rbuf, 5, contigs, 0, 0,
And observe the following error across all processes:
Rank 0 [Thu Jun 16 16:19:24 2016] [c0-0c2s9n1] Fatal error in MPI_Sendrecv: Invalid datatype, error stack:
MPI_Sendrecv(232): MPI_Sendrecv(sbuf=0x9ac440, scount=5, INVALID DATATYPE, dest=0, stag=0, rbuf=0x9ac4a0, rcount=5, INVALID DATATYPE, src=0, rtag=0, MPI_COMM_SELF, status=0x7fffffff6780) failed
Not sure what I am doing wrong. Do i need to further use "MPI_Type_create_resized " to register the "extent"? If so, an example quoting the above scenario would really help.
Also my main goal is to perform "MPI_Alltoallv" using a similar array of structs (of size ~ several thousands). Hopefully if I can get the SendRecv to work I can move on to "MPI_Alltoallv".
Any help would be highly appreciated.
The sendtype and recvtype parameters expect a parameter of type MPI_Datatype. What you're passing in is an array of these, i.e. a MPI_Datatype *.
You can only use one of these array elements at a time to pass to this function.

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.

How to MPI_SEND and MPI_RECV

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

Resources