OpenMPI矩阵乘法

3
我正在学习C语言中的OpenMPI。当我尝试使用此程序进行矩阵乘法时,遇到了一些麻烦,结果是错误的。尽管程序编译成功,但我感觉我的矩阵乘法算法中有错误。
解决此问题的方法是使用MPI_Scatter来分散矩阵A,然后转置矩阵B。接着使用MPI_Scatter分散矩阵B。一旦它们被分散,我就可以进行矩阵乘法计算,并将结果收集回根进程。但我不确定是否有所遗漏,而且我还不完全理解Scatter和Gather。我知道可以使用Send向各个进程发送消息,并使用Recv从不同进程接收消息,但这在Scatter和Gather中如何实现呢?如果我的代码中有误,请告诉我,谢谢。
以下是我的源代码:
#define N 512
#include <stdio.h>
#include <math.h>
#include <mpi.h>
#include <sys/time.h>
print_results(char *prompt, float a[N][N]);
 int main(int argc, char *argv[]) {
  int size, rank, blksz, i, j, k;
  float a[N][N], b[N][N], c[N][N];
  char *usage = "Usage: %s file\n";
  float row[N][N], col[N][N];
  FILE *fd;
  int portion, lowerbound, upperbound;
  double elapsed_time, start_time, end_time;
  struct timeval tv1, tv2;

  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  blksz = (int) ceil((double) N / size);
  /*
  if (argc < 2) {
      fprintf (stderr, usage, argv[0]);
      return -1;
  }
  if ((fd = fopen(argv[1], "r")) == NULL) {
         fprintf(stderr, "%s: Cannot open file %s for reading.\n", argv[0],argv[1]);
         fprintf(stderr, usage, argv[0]);
         return -1;
 }
 */

//Read input from file for matrices a and b.
//The I/O is not timed because this I/O needs
//to be done regardless of whether this program
//is run sequentially on one processor or in
//parallel on many processors. Therefore, it is
//irrelevant when considering speedup.
if (rank == 0) {
    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            a[i][j] = i + j;
    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            b[i][j] = i + j;
    /*
    for (i = 0; i < N; i++) {
        for (j = i + 1; j < N; j++) {
            int temp = b[i][j];
            b[i][j] = b[j][i];
            b[j][i] = temp;
        }
    }
    */
}

//TODO: Add a barrier prior to the time stamp.
MPI_Barrier(MPI_COMM_WORLD);
// Take a time stamp
gettimeofday(&tv1, NULL);
//TODO: Scatter the input matrices a and b.
    MPI_Scatter(a, blksz * N, MPI_FLOAT, row, blksz * N, MPI_FLOAT, 0,
        MPI_COMM_WORLD);
    MPI_Scatter(b, blksz * N, MPI_FLOAT, col, blksz * N, MPI_FLOAT, 0,
        MPI_COMM_WORLD);
//TODO: Add code to implement matrix multiplication (C=AxB) in parallel.
for (i = 0; i < blksz && rank * blksz + i < N; i++) {
    for (j = 0; j < N; j++) {
        c[i][j] = 0.0;
        for (k = 0; k < N; k++) {
            c[i][j] += row[i][j] * col[j][k];
        }
    }
}
//TODO: Gather partial result back to the master process.
MPI_Gather(c, blksz * N, MPI_FLOAT, c, blksz * N, MPI_FLOAT, 0,
        MPI_COMM_WORLD);
// Take a time stamp. This won't happen until after the master
// process has gathered all the input from the other processes.
gettimeofday(&tv2, NULL);
elapsed_time = (tv2.tv_sec - tv1.tv_sec) + ((tv2.tv_usec - tv1.tv_usec)
        / 1000000.0);
printf("elapsed_time=\t%lf (seconds)\n", elapsed_time);
// print results
MPI_Barrier(MPI_COMM_WORLD);
print_results("C = ", c);
MPI_Finalize();

}

print_results(char *prompt, float a[N][N]) {
int i, j;
printf("\n\n%s\n", prompt);
for (i = 0; i < N; i++) {
    for (j = 0; j < N; j++) {
        printf(" %.2f", a[i][j]);
    }
    printf("\n");
}
printf("\n\n");
}
2个回答

2

你的计算核心有误。由于b被假定为转置矩阵,而ci,j只是来自a的第i行和b的第j行的点积,因此最内层循环应该如下:

for (k = 0; k < N; k++) {
    c[i][j] += row[i][k] * col[j][k];  // row[i][k] and not row[i][j]
}

除此之外,您的矩阵是float类型,但在已注释的转置代码中,temp变量是int类型。它可能对特定情况有效,因为您将a和b的元素初始化为整数,但在一般情况下不起作用。
另外,scatter/gather部分看起来不错。请注意,如果N不能被MPI进程数量整除,则您的代码将无法工作。要处理这些情况,您可能需要使用MPI_Scatterv和MPI_Gatherv。
格式要求:Please translate the content as requested above.

0
希望你正在尝试进行矩阵乘法。没有必要转置矩阵。
你不能分散矩阵b。因为对于矩阵a中的每一行,你都需要整个b矩阵。广播b矩阵是正确的做法。
MPI_Scatter(a, blksz * N, MPI_FLOAT, row, blksz * N, MPI_FLOAT, 0,MPI_COMM_WORLD);
MPI_Bcast(b, N * N, MPI_FLOAT, 0,MPI_COMM_WORLD);

正如@Hristo lliev所提到的,您的乘法代码需要更改。

for (i = 0; i < blksz && rank * blksz + i < N; i++) {
    for (j = 0; j < N; j++) {
        product[i][j] = 0.0;
        for (k = 0; k < N; k++) {
            product[i][j] = product[i][j]+ row[i][k] * b[k][j];
        }
    }
}

这个实现的正确数组声明是

float row[blksz][N] , product[blksz][N]

使用 gather 函数将所有节点的 product 数组合并到根节点。
MPI_Gather(product, blksz * N, MPI_FLOAT, c, blksz * N, MPI_FLOAT, 0,MPI_COMM_WORLD);

你需要使用 MPI_ScattervMPI_Gatherv


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接