MPI Отправка массива массива - PullRequest
3 голосов
/ 01 марта 2012

хорошо, поэтому я пытаюсь отправить структуру, подобную таковой, по MPI

struct BColumns {
        double **B;
        int offset;
};

И если я просто сделаю какое-то распределение данных БС, например, так:

    bSet.offset = myRank;
    bSet.B = (double **) calloc(2, sizeof(double *));
    bSet.B[0] = (double *) calloc(1, sizeof(double));
    bSet.B[1] = (double *) calloc(1, sizeof(double));

    bSet.B[0][0] = 1;
    bSet.B[1][0] = 2;


    if(myRank == 0){
            MPI_Send(&bSet,sizeof(struct BColumns), MPI_BYTE, 1, 1, MPI_COMM_WORLD);
    }else{
            MPI_Recv(&recvBuf, sizeof(struct BColumns), MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status );
    }

И я предполагаю,что это не будет работать хорошо, потому что если я отправлю эту структуру как есть, она просто отправит указатель в B, и этот указатель не будет указывать на что-либо на другом процессоре, так как я буду отправлять подобные данные в MPI.

Ответы [ 2 ]

4 голосов
/ 01 марта 2012

Как указывает suszterpatt, вы действительно хотите выделить свой блок B в один большой блок;в любом случае, это, вероятно, лучше для производительности, но это действительно необходимо для любых коммуникаций, поэтому вы не гонитесь за указателями повсюду.И я думаю, что так или иначе вам, вероятно, придется делать это разными посылками - отправлять информацию о размере, а затем данные в одном чанке - хотя вы, вероятно, могли бы создать и удалить разные MPI_Type_struct для каждого из этихОтправить.Но использовать несколько посылок для каждого объекта не очень сложно:

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

typedef struct BColumns {
        double **B;
        int offset;
} bc;

double **alloc2d(int n, int m) {
    double *data = malloc(n*m*sizeof(double));
    double **array = malloc(n*sizeof(double *));
    for (int i=0; i<n; i++) {
        array[i] = &(data[i*m]);
    }
    return array;
}

void free2d(double **array) {
    free(array[0]);
    free(array);
}

int main(int argc, char **argv) {

    const int tag = 13;
    int size, rank;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (size < 2) {
        fprintf(stderr,"Requires at least two processes.\n");
        exit(-1);
    }

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        int ncols=3, colsize=5;
        bc *send;

        send = malloc(sizeof(bc));
        send->offset = 1;
        send->B = alloc2d(ncols, colsize);
        for (int i=0; i<ncols; i++)
            for (int j=0; j<colsize; j++)
                send->B[i][j] = i*j;

        const int dest = 1;
        MPI_Send(&ncols,   1, MPI_INT, dest, tag, MPI_COMM_WORLD);
        MPI_Send(&colsize, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
        MPI_Send(&(send->offset), 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
        MPI_Send(&(send->B[0][0]), ncols*colsize, MPI_DOUBLE, dest, tag,
                 MPI_COMM_WORLD);


        printf("Rank %d: sent structure B\n", rank);
        free2d(send->B);
        free(send);
    }

    if (rank == 1) {
        MPI_Status status;
        const int src=0;
        int rncols, rcolsize;
        bc *recv;

        MPI_Recv(&rncols,   1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
        MPI_Recv(&rcolsize, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
        printf("Rank %d: Received: rncols = %d rcolsize=%d\n", rank, rncols, rcolsize);

        recv = malloc(sizeof(bc));
        recv->B = alloc2d(rncols, rcolsize);

        MPI_Recv(&(recv->offset), 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
        MPI_Recv(&(recv->B[0][0]), rncols*rcolsize, MPI_DOUBLE, src, tag,
                MPI_COMM_WORLD, &status);

        printf("Rank %d: Received: offset = %d\n", rank, recv->offset);
        for (int i=0; i<rncols; i++) {
            printf("%d:  Column %d/%d: ", rank, i, rncols);
            for (int j=0; j<rcolsize; j++)
                printf(" %lf ", recv->B[i][j]);
            printf("\n");
        }

        free2d(recv->B);
        free(recv);
    }

    MPI_Finalize();

    return 0;
}

И затем запустить его:

$ mpirun -np 3 ./bstruct
Rank 0: sent structure B
Rank 1: Received: rncols = 3 rcolsize=5
Rank 1: Received: offset = 1
1:  Column 0/3:  0.000000  0.000000  0.000000  0.000000  0.000000 
1:  Column 1/3:  0.000000  1.000000  2.000000  3.000000  4.000000 
1:  Column 2/3:  0.000000  2.000000  4.000000  6.000000  8.000000 

Вы можете объединить эти данные в одно сообщение, если хотите избежать задержкинескольких посылок (и если вы знали заранее максимальный размер для массива B) либо вручную, либо с использованием вызовов функций MPI или типов данных, но вам все равно придется делать это аналогичным образом.

2 голосов
/ 01 марта 2012

Самый простой способ - использовать один массив для хранения ваших значений в порядке строк / столбцов, так чтобы все они были непрерывными в памяти.Затем вам просто нужно определить тип данных MPI, который описывает структуру памяти структуры (множество значений типа double и int).

...