【问题标题】:MPI Scatter/Gather scope of variablesMPI Scatter/Gather 变量范围
【发布时间】:2017-08-27 09:47:06
【问题描述】:

我正在处理 BML 自动机的 MPI 版本,但 MPI_Scatter() 无法按预期工作。我读到here,对于集体通信功能,每个进程都需要它的数组副本,只需要分配的空间而无需初始化。在我的代码中有一个子网格local_grid,每个进程都在操作,还有一个起始大grid,只有根操作。我的意思是使用 MPI Datatype 的 Scatter-Gather 通信。我为每个网格和子网格分配空间,然后仅为根初始化网格。我哪里错了?

        unsigned char*** local_grid;
        unsigned char** grid;

        MPI_Status stat;
        MPI_Datatype rowtype;

        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &nproc);
        local_n = N / nproc;

        MPI_Type_contiguous(N + 2,    /* count */
                MPI_UNSIGNED_CHAR,    /* oldtype */
                &rowtype              /* newtype */
                );
        MPI_Type_commit(&rowtype);

        /* Allocate space for 3D local grids*/
        local_grid = (unsigned char***)malloc(2 * sizeof(unsigned char**));
        for(i = 0; i < 2; i++) {
            local_grid[i] = (unsigned char**)malloc((local_n + 2) * sizeof(unsigned char*));
            for(j = 0; j < local_n + 2; j++) {
                local_grid[i][j] = (unsigned char*)malloc((N + 2) * sizeof(unsigned char));
            }
        }
        /* Initialize local grids*/
        for(i = 0; i < local_n + 2; i++) {
            for(j = 0; j < N + 2; j++) {
                local_grid[0][i][j] = 0;
                local_grid[1][i][j] = 0;
            }
        }
        /* Allocate 2D starting grid */
        grid = (unsigned char**)malloc(N * sizeof(unsigned char*));
        for(i = 0; i < N + 2; i++) {
            grid[i] = (unsigned char*)malloc((N + 2) * sizeof(unsigned char));
        }
        /* Root */
        if(rank == 0) {
            /* initialize 2D starting grid */
            for(i = 0; i < N; i++) {
                for(j = 0; j < N + 2; j++) {
                    grid[i][j] = (((float)rand())/RAND_MAX) > rho ? 0 : rand()%2 + 1;
                    grid[i][0] = grid[i][N+1] = 0;
                    printf("%2d ", grid[i][j]);
                }
                printf("\n");
            }
        }
        /* All */
        MPI_Scatter(grid[0], local_n, rowtype, local_grid[cur][1], local_n, rowtype, source, MPI_COMM_WORLD);

        ...

程序正确终止,但只有一个 rowtype 行从 Scatter() 传递到根进程,尽管数量多少,但没有传递给任何其他进程。

【问题讨论】:

    标签: c malloc mpi scatter


    【解决方案1】:

    一个问题来自您声明/分配二维数组的方式。

    您将二维数组声明为指向数组的指针数组(例如矩阵行),但 MPI 需要连续布局。

    例如,你可以替换

    grid = (unsigned char**)malloc(N * sizeof(unsigned char*));
    for(i = 0; i < N; i++) {
        grid[i] = (unsigned char*)malloc((N + 2) * sizeof(unsigned char));
    }
    

    与

        grid = (unsigned char**)malloc(N * sizeof(unsigned char*));
        grid[0] = (unsigned char*)malloc(N*(N+2)*sizeof(unsigned char));
        for(i = 1; i < N; i++) {
            grid[i] = grid[i-1] + N + 2;
        }
    

    然后使用grid[0] 作为MPI_Scatter() 或MPI_Gather() 的缓冲区参数 local_grid[0] 和 local_grid[1] 必须应用相同的东西

    当你需要释放网格时,你可以简单地

    free(grid[0]);
    free(grid);
    

    请注意,如果N 不是nproc 的倍数,我认为您的程序无法正常工作

    【讨论】:

    • 循环内部发生了什么?因此,如果您想在不知道参数的情况下在 MPI_Gather/Scatter 函数中传递 2D 或 3D 子网格,这是您会做的典型方式吗?稍后我会修复 N/nproc 细节,我知道。
    • 很抱歉,我很难理解您的评论。 grid 是一个指针数组。由于您在 MPI 中使用它,因此您需要确保 grid[1][0] 就在 grid[0][N+1] 旁边。我描述的方法正是这样做的:一次分配完整的数组,然后构建指针数组,使它们都指向完整的数组。顺便说一句,我刚刚注意到你的分配有一个错误,我重复了一遍:应该是for(i=0; i&lt;N; i++)
    • 好的,所以对于 3D 数组 grid[1][0][0] 应该在 grid[0][N+1][N+1] 旁边?我不知道怎么写,我想用一个嵌套循环(?)。
    • “在 C 中,二维数组实际上是一个指针数组” - 不正确。 C 中任何维度的内在数组(例如int a[M][N][P])都是连续的。当具体实现为指针数组时,不连续是多维数组。在现代 C 方言中,最简洁的选择(在我自己看来)是使用指向给定维度数组的指针,例如int (*grid)[M][N][P] = malloc(...).
    • 没有必要。 C99 允许不同大小的数组,并且当 M、N 和 P 的值仅在运行时已知时,这种方式也适用。唯一的问题是 C11 将其作为可选功能。
    猜你喜欢
    • 2014-09-27
    • 1970-01-01
    • 2020-05-07
    • 2019-09-10
    • 1970-01-01
    • 2019-01-13
    • 2016-10-02
    • 2015-11-26
    • 2020-05-03
    相关资源
    最近更新 更多