【问题标题】:MPI_Scatterv doesn't workMPI_Scatterv 不起作用
【发布时间】:2016-02-10 10:04:24
【问题描述】:

我用 C/MPI 编写了一个程序,它简单地将 NxN 矩阵拆分为子矩阵(用于行),然后使用例程 MPI_Scatterv 将其提供给所有进程。维度 N 不一定是进程数的倍数。我决定为等于 DIM % 大小的进程再分配一行。代码如下;它不起作用,我不明白为什么。错误消息是这样的: 工作中止: 等级:节点:退出代码[:错误消息] 0: PACI: -1073741819: 进程 0 退出而不调用 finalize

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

#define DIM 4
#define ROOT 0

float **alloc (int, int);
void init (float **, int, int);
void print (float **, int, int);

int main(int argc, char *argv[])
{
    int rank,               
    size,               
    dimrecv,
    i;                  
    int *sendcount = NULL, *displs = NULL;
    float **matrix, **recvbuf;  

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

    dimrecv = (int)(DIM / size);
    if(rank < (DIM % size))
        dimrecv += 1 ;
    recvbuf = alloc(dimrecv, DIM); 

    if (rank == ROOT) 
    {
        matrix = alloc(DIM, DIM);
        init(matrix, DIM, DIM);
        sendcount = (int*)calloc(size, sizeof(int));
        displs = (int*)calloc(size, sizeof(int));
        int total = 0;
        printf("MATRIX %d x %d", DIM, DIM);
        print(matrix, DIM, DIM);

        displs[0] = 0;
        for (i = 0; i < size; i++)
        {
            if (i < DIM % size)
                sendcount[i] = (ceil((float)DIM/size))*DIM;
            else
                sendcount[i] = (floor((float)DIM/size))*DIM;
            total += sendcount[i];
            if (i + 1 < size)
                displs[i + 1] = total;
        }
    }
MPI_Scatterv(&(matrix[0][0]), sendcount, displs, MPI_FLOAT,
             recvbuf, dimrecv*DIM, MPI_FLOAT, ROOT, MPI_COMM_WORLD);

printf("\n\n");

for(i = 0; i< size; i++)
{
    MPI_Barrier(MPI_COMM_WORLD);
    if (i == rank)
    {
        printf("SUBMATRIX P%d", i);
        print(recvbuf, dimrecv, DIM);
    }
}

free(matrix[0]);
free(matrix);
free(recvbuf[0]);
free(recvbuf);
/* quit */
MPI_Finalize();
return 0;
}

float **alloc(int rows, int cols)
{
    int i;
    float *num_elem = (float *)calloc(rows*cols, sizeof(float));
    float **matrix= (float **)calloc(rows, sizeof(float*));
    for (i=0; i<rows; i++)
        matrix[i] = &(num_elem[cols*i]);

    return matrix;
}

void init (float **matrix, int rows, int cols)
{
    int i, j;
    srand(time(NULL));
    for (i = 0; i < rows; i++) {
        for (j = 0; j < cols; j++)
            matrix[i][j] = 1 + (rand() % 5);
    }
}

void print (float **matrix, int rows, int cols)
{
int i, j;
for (i = 0; i < rows; i++) {
        printf("\n");
        for (j = 0; j < cols; j++)
            printf("%.1f ", matrix[i][j]);
    }
}

如何使用双指针动态分配来解决这个问题?我以静态方式编写了相同的程序并且它有效!非常感谢。 人。

【问题讨论】:

  • 只有排名 0 的内存分配给 sendcountdispls。您需要首先让其他等级为这些指针分配内存,然后MPI_Broadcast 它们应该具有的值(并且由等级 0 计算)。附带说明一下,转换 malloccalloc 和 co 的结果通常被认为是不好的形式。

标签: c mpi


【解决方案1】:

您需要更加小心哪个进程/等级正在分配内存,以及哪个进程/等级因此正在释放内存。

在您当前的实现中,您需要rank == ROOT 分配和初始化matrixsendcountdispls。您将希望每个等级分配和初始化sendcountdispls(否则,当他们每个人输入MPI_Scatterv 时,他们怎么知道他们将收到什么?)。最后,他们还需要分配但初始化recvbuf。此缓冲区的初始化发生在 MPI_Scatterv 例程内部。

[旁注:从技术上讲,您不需要让每个等级初始化sendcountdispls,尽管这肯定是最快的。如果只有rank == ROOT 进程知道计算这些值,那么在进入MPI_Scatterv 例程之前,您必须将这两个数组MPI_Bcast 分配给每个进程。]

当然,您必须确保只有正确的等级才能释放他们之前分配的正确内存。

这在您的静态初始化中起作用的原因是,当您最初静态定义数组时,每个等级都“分配”了内存。假设您天真地这样做了,您可能以前在该实现中使用了过多的内存(因为,如上所示,并非每个等级都需要为您正在使用的每个矩阵/数组分配内存)。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    感谢鼻子的建议。然而,该程序并不能很好地运行。修改后的代码如下:

    ...
    MPI_Bcast(sendcount, 4, MPI_INT, ROOT, MPI_COMM_WORLD);
    MPI_Bcast(displs, 4, MPI_INT, ROOT, MPI_COMM_WORLD);
    
    MPI_Scatterv(&(matrix[0][0]), sendcount, displs, MPI_FLOAT,
                 recvbuf, dimrecv*DIM, MPI_FLOAT, ROOT, MPI_COMM_WORLD);
    
    printf("\n\n");
    for(i = 0; i< size; i++)
    {
        MPI_Barrier(MPI_COMM_WORLD);
        if (i == rank)
        {
            printf("SUBMATRIX P%d", i);
            print(recvbuf, dimrecv, DIM);
        }
    }
    if (rank == ROOT) {
        for (i=0; i<DIM; i++)
            free(matrix[i]);
        free(matrix);
    }
    for(i=0; i<dimrecv; i++)
        free(recvbuf[i]);
    free(recvbuf);
    free(sendcount);
    free(recvbuf);
    

    sendcount 和 displs 已分配到 ROOT 级别的可见性之外。代码中一定有我没有发现的错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-18
      • 2021-04-17
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 2016-03-13
      相关资源
      最近更新 更多