MPI聚集多个向量

时间:2014-12-19 10:46:46

标签: c mpi hpc

我试图从MPI配置中的节点收集一些不同矩阵的行。到目前为止,我已经让程序使用下面的代码接收一行到另一个进程,即代码会将矩阵recv更改为数字1..7,但理想情况是我和#39 ; d喜欢这样做是改变前两行,第一行是1..7,第二行是8..14,但是当我更改发送/接收计数时,这不会发生第55/57行。这些街区应该在记忆中连续布局,所以我不确定我目前在哪里出错,任何帮助都会受到赞赏。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
double **allocMatrix(int dim) {
    int i;
    double **matrix;
    matrix = (double **)malloc(dim*sizeof(double *));
    for(i=0; i < dim; i++) {
        matrix[i] = (double *)malloc(dim*sizeof(double));
    }
    return matrix;
}
void printMatrix(double **values, int size) {
    int i, j;

    for (i = 0; i < size; i++) {
        for (j = 0; j < size; j++) {
            printf("%10lf ", values[i][j]);
        }
        printf("\n");
    }
}
int main(int argc, char* argv[]) {
    MPI_Init(&argc, &argv);
    int size, rank, i, j;
    int dimensions = 7;
    MPI_Comm_size(MPI_COMM_WORLD, &size);//number of processes
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);//rank for each process

    double **send = allocMatrix(dimensions);
    double **recv = allocMatrix(dimensions);
    int count = 0;
    for (i=0; i<dimensions; i++) {
        for (j=0; j<dimensions; j++) {
            if (rank == 0) {
                recv[i][j] = 0;
            } else {
                send[i][j] = ++count;
            }
        }
    }

    MPI_Datatype arrType;
    MPI_Type_vector(1, dimensions, 0, MPI_DOUBLE, &arrType);
    MPI_Type_commit(&arrType);
    int recvCounts[size];
    int displs[size];
    recvCounts[0] = 0;
    displs[0] = 0;
    recvCounts[1] = 1;
    displs[1] = 0;
    MPI_Gatherv(&(send[0][0]), 1, arrType,
         &(recv[0][0]), recvCounts, displs, arrType,
         0, MPI_COMM_WORLD);

    if (rank == 0) {
        printMatrix(recv, dimensions);
    }


    MPI_Finalize();
    return 0;
}

输出:

make gatherv
mpicc -Wall -o gatherv gatherv.c && ./gather
  1.000000   2.000000   3.000000   4.000000   5.000000   6.000000   7.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 

期望的输出:

  1.000000   2.000000   3.000000   4.000000   5.000000   6.000000   7.000000 
  8.000000   9.000000   10.00000   11.00000   12.00000   13.00000   14.00000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 
  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000 

1 个答案:

答案 0 :(得分:1)

此代码中有两点可以修改:

  • 矩阵的分配效果很好,有时可能很有用,但行在内存中不连续,因为malloc()被称为dim+1次。您可以通过为like in this answer和其他许多值分配所有值的空间来确保行在内存中是连续的。这种2D数组是可以被像lapack和fftw这样的库使用的数组......而且MPI_Gatherv()也会喜欢它。 malloc()将被调用两次:一次用于指向行,一次用于值。

  • 如果更改recvCounts[]中的值,则要发送的项目数必须相应更改。由于所有进程都以相同的方式填充recvCounts[],并且由于接收类型和发送类型相同(arrType),因此使用recvCounts[rank]作为MPI_Gatherv()的第二个参数是好的伎俩。

顺便说一句,对于第一个问题来说这是一个非常好的问题!

这里的代码可由mpicc main.c -o main编译并由mpirun -np 42 main

运行
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
double **allocMatrix(int dim) {
    int i;
    double **matrix;
    //allocate space for values at once, so as to be contiguous in memory
    matrix = (double **)malloc(dim*sizeof(double *));
    matrix[0] = (double *)malloc(dim*dim*sizeof(double));
    for(i=1; i < dim; i++) {
        matrix[i]=&matrix[0][dim*i];
        //matrix[i] = (double *)malloc(dim*sizeof(double));
    }
    return matrix;
}
void printMatrix(double **values, int size) {
    int i, j;

    for (i = 0; i < size; i++) {
        for (j = 0; j < size; j++) {
            printf("%10lf ", values[i][j]);
        }
        printf("\n");
    }
}
//function to free the matrix
void freeMatrix(double **values) {
    free(values[0]);
    free(values);
}

int main(int argc, char* argv[]) {
    MPI_Init(&argc, &argv);
    int size, rank, i, j;
    int dimensions = 7;
    MPI_Comm_size(MPI_COMM_WORLD, &size);//number of processes
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);//rank for each process

    double **send = allocMatrix(dimensions);
    double **recv = allocMatrix(dimensions);
    int count = 0;
    for (i=0; i<dimensions; i++) {
        for (j=0; j<dimensions; j++) {
            if (rank == 0) {
                recv[i][j] = 0;
            } else {
                send[i][j] = ++count;
            }
        }
    }

    MPI_Datatype arrType;
    MPI_Type_vector(1, dimensions, 0, MPI_DOUBLE, &arrType);
    MPI_Type_commit(&arrType);
    int recvCounts[size];
    int displs[size];
    // a loop to initialize counts and displacements
    for(i=0;i<size;i++){
        recvCounts[i]=0;
        displs[i]=0;
    }
    recvCounts[0] = 0;
    displs[0] = 0;
    if(size>1){
        recvCounts[1] = 2;// two lines sent
        displs[1] = 0;//to the start of matrix
    }
    //second argument of mpi_gatherv() is now recvCounts[rank]
    MPI_Gatherv(&(send[0][0]), recvCounts[rank], arrType,
            &(recv[0][0]), recvCounts, displs, arrType,
            0, MPI_COMM_WORLD);

    if (rank == 0) {
        printMatrix(recv, dimensions);
    }

    //free the matrices
    freeMatrix(recv);
    freeMatrix(send);

    MPI_Finalize();
    return 0;
}