gpt4 book ai didi

c++ - OpenMP C++ 矩阵乘法并行运行较慢

转载 作者:IT老高 更新时间:2023-10-28 21:37:47 25 4
gpt4 key购买 nike

我正在学习使用 OpenMP 并行执行 for 循环的基础知识。

遗憾的是,我的并行程序运行速度比串行版本慢 10 倍。我究竟做错了什么?我错过了一些障碍吗?

double **basicMultiply(double **A, double **B, int size) {
int i, j, k;
double **res = createMatrix(size);
omp_set_num_threads(4);
#pragma omp parallel for private(k)
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
for (k = 0; k < size; k++) {
res[i][j] += A[i][k] * B[k][j];
}
}
}
return res;
}

非常感谢!

最佳答案

您的问题是由于内部循环变量 j 上的竞争条件造成的。它需要私有(private)化。

对于 C89,我会这样做:

#pragma omp parallel
{
int i, j, k;
#pragma omp for
for(i=0; ...

对于 C++ 或 C99,使用混合声明

#pragma omp parallel for
for(int i=0; ...

这样做您不必显式声明任何共享或私有(private)内容。

对您的代码的一些进一步评论。当您执行 B[k][j] 时,您的单线程代码对缓存不友好。这会读取一个高速缓存行,然后移动到下一个高速缓存行,依此类推,直到完成点积,此时其他高速缓存行已被逐出。相反,您应该先进行转置并以 BT[j][k] 的身份访问。此外,您分配了数组数组,而不是一个连续的二维数组。我修复了您的代码以使用转置和连续的二维数组。

这是我得到 size=512 的时间。

no transpose  no openmp 0.94s
no transpose, openmp 0.23s
tranpose, no openmp 0.27s
transpose, openmp 0.08s

下面是代码(另见 http://coliru.stacked-crooked.com/a/ee174916fa035f97)

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

void transpose(double *A, double *B, int n) {
int i,j;
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
B[j*n+i] = A[i*n+j];
}
}
}

void gemm(double *A, double *B, double *C, int n)
{
int i, j, k;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
double dot = 0;
for (k = 0; k < n; k++) {
dot += A[i*n+k]*B[k*n+j];
}
C[i*n+j ] = dot;
}
}
}

void gemm_omp(double *A, double *B, double *C, int n)
{
#pragma omp parallel
{
int i, j, k;
#pragma omp for
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
double dot = 0;
for (k = 0; k < n; k++) {
dot += A[i*n+k]*B[k*n+j];
}
C[i*n+j ] = dot;
}
}

}
}

void gemmT(double *A, double *B, double *C, int n)
{
int i, j, k;
double *B2;
B2 = (double*)malloc(sizeof(double)*n*n);
transpose(B,B2, n);
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
double dot = 0;
for (k = 0; k < n; k++) {
dot += A[i*n+k]*B2[j*n+k];
}
C[i*n+j ] = dot;
}
}
free(B2);
}

void gemmT_omp(double *A, double *B, double *C, int n)
{
double *B2;
B2 = (double*)malloc(sizeof(double)*n*n);
transpose(B,B2, n);
#pragma omp parallel
{
int i, j, k;
#pragma omp for
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
double dot = 0;
for (k = 0; k < n; k++) {
dot += A[i*n+k]*B2[j*n+k];
}
C[i*n+j ] = dot;
}
}

}
free(B2);
}

int main() {
int i, n;
double *A, *B, *C, dtime;

n=512;
A = (double*)malloc(sizeof(double)*n*n);
B = (double*)malloc(sizeof(double)*n*n);
C = (double*)malloc(sizeof(double)*n*n);
for(i=0; i<n*n; i++) { A[i] = rand()/RAND_MAX; B[i] = rand()/RAND_MAX;}

dtime = omp_get_wtime();
gemm(A,B,C, n);
dtime = omp_get_wtime() - dtime;
printf("%f\n", dtime);

dtime = omp_get_wtime();
gemm_omp(A,B,C, n);
dtime = omp_get_wtime() - dtime;
printf("%f\n", dtime);

dtime = omp_get_wtime();
gemmT(A,B,C, n);
dtime = omp_get_wtime() - dtime;
printf("%f\n", dtime);

dtime = omp_get_wtime();
gemmT_omp(A,B,C, n);
dtime = omp_get_wtime() - dtime;
printf("%f\n", dtime);

return 0;

}

关于c++ - OpenMP C++ 矩阵乘法并行运行较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22634121/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com