[英]OpenMP C++ matrix multiplication
我想并行化以下代码。 尤其是这些for循环,因为这是最昂贵的操作。
for (i = 0; i < d1; i++)
for (j = 0; j < d3; j++)
for (k = 0; k < d2; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j];
这是我第一次尝试使用OpenMP并行化代码。 我已经尝试了几件事,但是与使用串行版本相比,我总是会遇到更糟糕的运行时。 如果您能告诉我代码或实用程序是否有问题,那将是很好的...
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
//#include <stdint.h>
// ---------------------------------------------------------------------------
// allocate space for empty matrix A[row][col]
// access to matrix elements possible with:
// - A[row][col]
// - A[0][row*col]
float **alloc_mat(int row, int col)
{
float **A1, *A2;
A1 = (float **)calloc(row, sizeof(float *)); // pointer on rows
A2 = (float *)calloc(row*col, sizeof(float)); // all matrix elements
//#pragma omp parallel for
for (int i=0; i<row; i++)
A1[i] = A2 + i*col;
return A1;
}
// ---------------------------------------------------------------------------
// random initialisation of matrix with values [0..9]
void init_mat(float **A, int row, int col)
{
//#pragma omp parallel for
for (int i = 0; i < row*col; i++)
A[0][i] = (float)(rand() % 10);
}
// ---------------------------------------------------------------------------
// DEBUG FUNCTION: printout of all matrix elements
void print_mat(float **A, int row, int col, char *tag)
{
int i, j;
printf("Matrix %s:\n", tag);
for (i = 0; i < row; i++)
{
//#pragma omp parallel for
for (j=0; j<col; j++)
printf("%6.1f ", A[i][j]);
printf("\n");
}
}
// ---------------------------------------------------------------------------
int main(int argc, char *argv[])
{
float **A, **B, **C; // matrices
int d1, d2, d3; // dimensions of matrices
int i, j, k; // loop variables
double start, end;
start = omp_get_wtime();
/* print user instruction */
if (argc != 4)
{
printf ("Matrix multiplication: C = A x B\n");
printf ("Usage: %s <NumRowA>; <NumColA> <NumColB>\n",argv[0]);
return 0;
}
/* read user input */
d1 = atoi(argv[1]); // rows of A and C
d2 = atoi(argv[2]); // cols of A and rows of B
d3 = atoi(argv[3]); // cols of B and C
printf("Matrix sizes C[%d][%d] = A[%d][%d] x B[%d][%d]\n",
d1, d3, d1, d2, d2, d3);
/* prepare matrices */
A = alloc_mat(d1, d2);
init_mat(A, d1, d2);
B = alloc_mat(d2, d3);
init_mat(B, d2, d3);
C = alloc_mat(d1, d3); // no initialisation of C,
//because it gets filled by matmult
/* serial version of matmult */
printf("Perform matrix multiplication...\n");
int sum;
//#pragma omp parallel
//{
#pragma omp parallel for collapse(3) schedule(guided)
for (i = 0; i < d1; i++)
for (j = 0; j < d3; j++)
for (k = 0; k < d2; k++){
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
//}
end = omp_get_wtime();
/* test output */
print_mat(A, d1, d2, "A");
print_mat(B, d2, d3, "B");
print_mat(C, d1, d3, "C");
printf("This task took %f seconds\n", end-start);
printf ("\nDone.\n");
return 0;
}
正如注释中所建议的那样,矩阵的大小可能足够小,以至于初始化附加线程的开销大于并行计算矩阵乘法所节省的时间。 但是,请考虑以下图表,其中包含我通过在有和没有OpenMP的情况下运行代码所获得的数据。
我使用从n = 10到n = 1000的平方矩阵。 请注意,并行版本如何在n = 50到n = 100之间变得更快。
但是,在尝试编写快速矩阵乘法时,还需要考虑其他问题,这主要与有效使用缓存有关。 首先,您连续分配整个矩阵(这很好),但是仍然使用两个指针重定向来访问数据,这是不必要的。 此外,矩阵以行主格式存储,这意味着您将连续访问A和C中的数据,而不是B中的数据。与其显式存储B并将A的行与B的列相乘,不如将其存储为A。通过存储B转置并将B的A元素行与B的换行相乘,可以更快地进行乘法。
这是仅针对A * B的优化,但是,在代码中可能还有其他地方存储B比B转置更好,在这种情况下,经常通过分块进行矩阵乘法可以提高缓存利用率
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.