1

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;
}
1
  • this line: MPI_Datatype myStruct; just creates an instance of a MPI_Datatype, Not a struct definition. Commented Dec 24, 2014 at 17:44

3 Answers 3

3

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 );
Sign up to request clarification or add additional context in comments.

3 Comments

Ok, I understand. But, how am I supposed to do this if I need a buffer and I need it to store data of my own type (struct)?
This link should get you started on how to create your own custom structs: tutorialspoint.com/cprogramming/c_typedef.htm
Thank you very much - now I've rewritten the code, but Segmentation fault is the new error :-) - in the main description
2

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.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.