嘿伙计们我正在尝试用C学习OpenMPI。当我这样做时,我在使用这个程序进行矩阵乘法时遇到了一些麻烦,结果是错误的。程序编译,但我觉得我的矩阵乘法算法在某处错了。
我解决这个问题的方法是使用MPI_Scatter散布矩阵A然后转置矩阵B.然后MPI_Scatter矩阵B.一旦它们被分散,我就进行矩阵乘法计算并将结果收集回根进程。我不确定我是否遗漏了什么,但我还不完全了解Scatter and Gather。我知道发送你可以发送到不同进程的各个进程和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");
}
答案 0 :(得分:2)
你的计算内核是错误的。由于b
被认为是转置而c i,j 只是来自i
的行a
和来自{{1}的行j
的点积最内层的循环应该是:
b
此外,您的矩阵为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
不能通过MPI进程的数量进行分解,那么您的代码将无效。要处理这些情况,您可能需要查看使用N
和MPI_Scatterv
。
答案 1 :(得分: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_Scatterv
和MPI_Gatherv