MPI_Get 没有在两个进程的缓冲区之间发送正确的元素

MPI_Get doesn't send the correct elements between the buffers of two process

我正在尝试创建一个程序,最终将在 MPI 中转置矩阵,以便它可以用于进一步的计算。但是现在我正在尝试做一件简单的事情:根进程有一个 4x4 矩阵 "A",其中包含按行优先顺序排列的元素 0..15。此数据分散到 2 个进程,以便每个进程接收矩阵的一半。进程 0 有一个 2x4 sub_matrix "a" 并接收元素 0..7,进程 1 在其 sub_matrix "a".

中接收元素 8..15

我的目标是让这些进程使用 MPI_Get 相互交换它们的 a 矩阵。由于我遇到了问题,我决定测试一个更简单的版本并简单地让进程 0 获取进程 1 的 "a" 矩阵,这样,一旦我在之后打印,这两个进程将在各自的 sub_matrices 中具有相同的元素MPI_Get-call 和 MPI_fence 被调用。

但输出不稳定,已尝试排除故障几个小时,但未能解决问题。非常感谢您对此的帮助。

这是下面的代码,运行-命令:mpi运行 -n 2 ./get

编译:mpicc -std=c99 -g -O3 -o get get.c -lm

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

#define NROWS 4
#define NCOLS 4

int allocate_matrix(int ***M, int ROWS, int COLS) {
  int *p;
  if (NULL == (p = malloc(ROWS * COLS * sizeof(int)))) {
    perror("Couldn't allocate memory for input (p in allocate_matrix)");
    return -1;
  }

  if (NULL == (*M = malloc(ROWS * sizeof(int*)))) {
    perror("Couldn't allocate memory for input (M in allocate_matrix)");
    return -1;
  }

  for(int i = 0; i < ROWS; i++) {
    (*M)[i] = &(p[i * COLS]);
  }
  return 0;
}

int main(int argc, char *argv[])
{
  int rank, nprocs, **A, **a, n_cols, n_rows, block_len;
  MPI_Win win;
  int errs = 0;

  if(rank==0)
    {
      allocate_matrix(&A, NROWS, NCOLS);
      for (int i=0; i<NROWS; i++)
        for (int j=0; j<NCOLS; j++)
          A[i][j] = i*NCOLS + j;
    }

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

  n_cols=NCOLS; //cols in a sub_matrix
  n_rows=NROWS/nprocs; //rows in a sub_matrix
  block_len = n_cols*n_rows;

  allocate_matrix(&a, n_rows, n_cols);
  for (int i = 0; i <n_rows; i++) 
    for (int j = 0; j < n_cols; j++) 
      a[i][j] = 0;


  MPI_Datatype block_type;
  MPI_Type_vector(n_rows, n_cols, n_cols, MPI_INTEGER, &block_type);
  MPI_Type_commit(&block_type);

  MPI_Scatter(*A, 1, block_type, &(a[0][0]), block_len, MPI_INTEGER, 0, MPI_COMM_WORLD);

  MPI_Barrier(MPI_COMM_WORLD);

  printf("process %d: \n", rank);
  for (int j=0; j<n_rows; j++){
    for (int i=0; i<n_cols; i++){
      printf("%d ",a[j][i]);
    }
    printf("\n");
  }


  if (rank == 0)
    {
      printf("TESTING, before Get a[0][0] %d\n", a[0][0]);
      MPI_Win_create(NULL, 0, 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
      MPI_Win_fence((MPI_MODE_NOPUT | MPI_MODE_NOPRECEDE), win);
      MPI_Get(*a, 8, MPI_INTEGER, 1, 0, 8, MPI_INTEGER, win);
      MPI_Win_fence(MPI_MODE_NOSUCCEED, win);

      printf("TESTING, after Get a[0][0] %d\n", a[0][0]);

      printf("process %d:\n", rank);
      for (int j=0; j<n_rows; j++){
        for (int i=0; i<n_cols; i++){
          printf("%d ", a[j][i]);
        }
        printf("\n");
      }

    }
  else
    { /* rank = 1 */
      MPI_Win_create(a, n_rows*n_cols*sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
      MPI_Win_fence((MPI_MODE_NOPUT | MPI_MODE_NOPRECEDE), win);
      MPI_Win_fence(MPI_MODE_NOSUCCEED, win);
    }


  MPI_Type_free(&block_type);
  MPI_Win_free(&win);
  MPI_Finalize();
  return errs;
}

这是我得到的输出:

process 0: 
0 1 2 3 
4 5 6 7 

process 1: 
8 9 10 11 
12 13 14 15 

process 0:
1552976336 22007 1552976352 22007 
1552800144 22007 117 0 

但我想要的是第二次从进程 0 打印矩阵,它应该具有与进程 1 相同的元素。

首先,我怀疑这真的是您正在测试的代码。您正在释放一些未定义的 MPI 类型变量,并且 rank

中未初始化
if(rank==0)
  {
    allocate_matrix(&A, NROWS, NCOLS);
    for (int i=0; i<NROWS; i++)
      for (int j=0; j<NCOLS; j++)
        A[i][j] = i*NCOLS + j;
  }

和代码段错误,因为 A 不会在根中分配。

移动此 post MPI_Comm_rank(),释放正确的 MPI 类型变量,并修复对 MPI_Win_create 的调用 1:

  MPI_Win_create(&a[0][0], n_rows*n_cols*sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
  // This -------^^^^^^^^

生成您正在寻找的结果。

我建议在数组的开头使用单一符号,例如 &a[0][0] 而不是 *a&a[0][0] 的混合。这将防止(或至少减少)类似错误的发生。