如何在MPI中分配奇数个处理器核心时分发数据?

时间:2015-10-23 08:28:36

标签: c mpi

我是MPI编程的初学者。我试图编写一个程序,动态地接收不同大小的一维数组(100,1000,10000,1000000的倍数等)并将其分散到分配的处理器核心。处理器内核计算接收元素的总和并将总和发回。根进程打印输入数组中元素的总和。

我使用MPI_Scatter()MPI_Reduce()来解决问题。但是,当分配的处理器内核数量为奇数时,某些数据会被遗漏。例如,当我输入数据大小为100和3个进程时 - 只添加了99个元素,最后一个元素被省略。

我搜索了替代方案,发现MPI_Scatterv()可用于数据的不均匀分布。但是没有任何材料可以指导我实施它。有人能帮我吗?我在这里发布我的代码。提前谢谢。

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

void readArray(char * fileName, double ** a, int * n);
int Numprocs, MyRank;
int mpi_err; 
#define Root = 0

void init_it(int  *argc, char ***argv) {
    mpi_err = MPI_Init(argc, argv);
    mpi_err = MPI_Comm_rank(MPI_COMM_WORLD, &MyRank);
    mpi_err = MPI_Comm_size(MPI_COMM_WORLD, &Numprocs);
}

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

    /* .......Variables Initialisation ......*/
    int        index; 
    double    *InputBuffer, *RecvBuffer, sum=0.0, psum = 0.0;
    double     ptime = 0.0, Totaltime= 0.0,startwtime = 0.0, endwtime = 0.0;
    int        Scatter_DataSize;
    int        DataSize;
    FILE       *fp;

    init_it(&argc,&argv);
    if (argc != 2) {
        fprintf(stderr, "\n*** Usage: arraySum <inputFile>\n\n");
        exit(1);
    }

    if (MyRank == 0) {
        startwtime = MPI_Wtime();
        printf("Number of nodes running %d\n",Numprocs);
        /*...... Read input....*/
        readArray(argv[1], &InputBuffer, &DataSize);
        printf("Size of array %d\n", DataSize);
    }

    if (MyRank!=0) {
        MPI_Recv(&DataSize, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, NULL);
    }
    else {
        int i;
        for (i=1;i<Numprocs;i++) {
            MPI_Send(&DataSize, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            d[i]= i*Numprocs;
        }
    }

    Scatter_DataSize = DataSize / Numprocs;
    RecvBuffer = (double *)malloc(Scatter_DataSize * sizeof(double));
    MPI_Barrier(MPI_COMM_WORLD);

    mpi_err = MPI_Scatter(InputBuffer, Scatter_DataSize, MPI_DOUBLE,
                          RecvBuffer, Scatter_DataSize, MPI_DOUBLE,
                          0, MPI_COMM_WORLD);
    for (index = 0; index < Scatter_DataSize; index++) {
        psum = psum + RecvBuffer[index];
    }

    //printf("Processor %d computed sum %f\n", MyRank, psum);

    mpi_err = MPI_Reduce(&psum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

    if (MyRank == 0) {
        endwtime = MPI_Wtime();
        Totaltime = endwtime - startwtime;
        printf("Total sum %f\n",sum);
        printf("Total time %f\n", Totaltime);
    }

    MPI_Finalize();
    return 0;
}


void readArray(char * fileName, double ** a, int * n) {
    int count, DataSize;
    double * InputBuffer;
    FILE * fin;

    fin = fopen(fileName, "r");
    if (fin == NULL) {
        fprintf(stderr, "\n*** Unable to open input file '%s'\n\n",
                fileName);
        exit(1);
    }

    fscanf(fin, "%d\n", &DataSize);
    InputBuffer = (double *)malloc(DataSize * sizeof(double));
    if (InputBuffer == NULL) {
        fprintf(stderr, "\n*** Unable to allocate %d-length array", DataSize);
        exit(1);
    }

    for (count = 0; count < DataSize; count++) {
        fscanf(fin, "%lf", &InputBuffer[count]);
    }
    fclose(fin);

    *n = DataSize;
    *a = InputBuffer;
}

2 个答案:

答案 0 :(得分:0)

Scatter_Datasize的计算:

Scatter_DataSize = DataSize / Numprocs;

只有当DataSize是Numprocs的倍数时,

才是正确的,在你的情况下,当Numprocs是偶数时,因为DataSize总是偶数。当Numprocs是奇数时你应该明确地计算余数并将其分配给一个MPI过程,我建议最后一个。

答案 1 :(得分:0)

在您的情况下,您可以使用sendcount[] MPI_Scatterv数组进行游戏。实际上,一个简单的实现方法是计算类型Nelement的元素数量(比如说sendtype)所有进程但只有一个会有所启发。其中一个进程(例如最后一个进程)将获取剩余数据。在这种情况下,从sendcount[i] = Nelementi0的索引p-2的{​​{1}}是通讯器中的进程数,对于您p )。然后,流程MPI_COMM_WORLD将获得p-1。关于位移数组sendcount[p-1] = DataSize-Nelement*(p-1),您只需指定从中获取传出数据以处理i的位移(以元素数量)(参见[1]第161页)。对于前面的示例,这将是:

displs[]

如果您确定其他流程 for (i=0; i<p; ++i) displs[i]=Nelement*i; 必须计算其他数据,请考虑为流程q设置好displs[q+1] q+1

[1] MPI:消息传递接口标准(版本3.1):http://www.mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf