OpenMP并行化矩阵乘法三重for循环(性能问题)

时间:2011-01-18 16:54:28

标签: performance loops parallel-processing openmp matrix-multiplication

我正在编写一个使用OpenMP进行矩阵乘法的程序,为了方便缓存,实现乘法A x B(转置)行X行而不是经典的A x B行x列,以获得更好的缓存效率。这样做我遇到了一个有趣的事实,对我而言是不合逻辑的:如果在这段代码中我并行化extern循环,程序比我在最内层循环中放置OpenMP指令要慢,在我的计算机中,时间是10.9对8.1秒。

//A and B are double* allocated with malloc, Nu is the lenght of the matrixes 
//which are square

//#pragma omp parallel for
for (i=0; i<Nu; i++){
  for (j=0; j<Nu; j++){
    *(C+(i*Nu+j)) = 0.;
#pragma omp parallel for
    for(k=0;k<Nu ;k++){
      *(C+(i*Nu+j))+=*(A+(i*Nu+k)) * *(B+(j*Nu+k));//C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
  }
}

2 个答案:

答案 0 :(得分:4)

当您并行化外部循环并且编译器无法弄清楚并添加其他锁时,您可能在数据中有一些依赖项。

最有可能它决定不同的外循环迭代可以写入相同的(C+(i*Nu+j)),并添加访问锁以保护它。

如果您要并行化第二个循环,编译器可能会发现没有依赖关系。但是,弄清楚没有依赖于并行化外部循环对于编译器来说并不是那么简单。

<强>更新

一些性能测量。

你好。它看起来像1000双*+不足以支付线程同步的成本。

我做了一些小测试,简单的向量标量乘法对openmp无效,除非元素的数量小于~10'000。基本上,阵列越大,使用openmp就会获得更高的性能。

因此,并行化最内部循环,您必须在不同线程之间分离任务,并将数据收集回1000'000次。

PS。尝试使用英特尔ICC,它可以免费用于学生和开源项目。我记得使用openmp来填充更小的10'000元素阵列。

更新2:缩减示例

    double sum = 0.0;
    int k=0;
    double *al = A+i*Nu;
    double *bl = A+j*Nu;
    #pragma omp parallel for shared(al, bl) reduction(+:sum)
    for(k=0;k<Nu ;k++){
        sum +=al[k] * bl[k]; //C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
    C[i*Nu+j] = sum;

答案 1 :(得分:4)

尝试不经常点击结果。这会导致高速缓存行共享并阻止操作并行运行。使用局部变量将允许大多数写入发生在每个核心的L1缓存中。

此外,使用restrict可能有所帮助。否则,编译器无法保证对C的写入不会更改AB

尝试:

for (i=0; i<Nu; i++){
  const double* const Arow = A + i*Nu;
  double* const Crow = C + i*Nu;
#pragma omp parallel for
  for (j=0; j<Nu; j++){
    const double* const Bcol = B + j*Nu;
    double sum = 0.0;
    for(k=0;k<Nu ;k++){
      sum += Arow[k] * Bcol[k]; //C(i,j)=sum(over k) A(i,k)*B(k,j)
    }
    Crow[j] = sum;
  }
}

此外,我认为如果你并行化最内层的循环,Elalfer对于需要减少是正确的。