arraysmpisendstride

MPI - Sending segments of an array


So I have an array of doubles. I would like to send, say every 5th double, to the receiving process. So essentially, I need a way of sending specific doubles with strides between them. Is there a function to do this, apart from storing the doubles into a send buffer? Would it be better to make my own derived type?


Solution

  • You should definitely create an MPI data type; it gives the MPI library an opportunity to avoid the extra copy for marshaling from the array, and it's pretty straightforward to do using, in this case, MPI_Type_vector():

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    
    int main(int argc, char** argv)
    {
        int size, rank;
        const int bigsize=50;
        const int stride = 5;
        const int count = (bigsize + stride - 1)/stride;
    
        const int sender = 0;
        const int receiver = 1;
        const int mytag = 1;
    
        MPI_Init(&argc,&argv);
        MPI_Comm_size(MPI_COMM_WORLD,&size);
        MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    
        if (size < 2) {
            fprintf(stderr,"%s: Require at least two processors.\n", argv[0]);
            MPI_Finalize();
            exit(-1);
        }
    
    
        if(rank == sender)
        {
            double bigarray[bigsize];
            for (int i=0; i<bigsize; i++)
                bigarray[i] = 0.;
    
            for (int i=0; i<bigsize; i+=stride)
                bigarray[i] = i/stride;
    
            printf("[%d]: ", rank);
            for (int i=0; i<bigsize; i++)
                printf("%lf ", bigarray[i]);
            printf("\n");
    
            MPI_Datatype everyfifth;
    
            MPI_Type_vector( count, 1, stride, MPI_DOUBLE, &everyfifth);
            MPI_Type_commit(&everyfifth);
    
            MPI_Send(bigarray, 1, everyfifth, receiver, mytag, MPI_COMM_WORLD);
    
            MPI_Type_free(&everyfifth);
        }
        else if( rank == receiver )
        {
            double littlearray[count];
    
            MPI_Status status;
    
            MPI_Recv(littlearray, count, MPI_DOUBLE, sender, mytag,
                        MPI_COMM_WORLD, &status);
    
            printf("[%d]: ", rank);
            for (int i=0; i<count; i++)
                printf("%lf ", littlearray[i]);
            printf("\n");
        }
    
        MPI_Finalize();
    
        return 0;
    }
    

    Compiling and running gives

    $ mpicc -o vector vector.c -std=c99
    $ mpirun -np 2 ./vector
    [0]: 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 2.000000 0.000000 0.000000 0.000000 0.000000 3.000000 0.000000 0.000000 0.000000 0.000000 4.000000 0.000000 0.000000 0.000000 0.000000 5.000000 0.000000 0.000000 0.000000 0.000000 6.000000 0.000000 0.000000 0.000000 0.000000 7.000000 0.000000 0.000000 0.000000 0.000000 8.000000 0.000000 0.000000 0.000000 0.000000 9.000000 0.000000 0.000000 0.000000 0.000000 
    [1]: 0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 9.000000