下面的C ++代码片段为循环提供了一个嵌套的,在内层执行3x3矩阵乘法。
int main()
{
double sum = 0;
#pragma omp parallel for reduction(+: sum)
for (int i=0;i<30;i++)
{
double eledir[3][3], noddir[3][3];
for (int j=0;j<200000;++j)
{
eledir[0][0]=2*i+j; eledir[0][1]=2*i+j;
eledir[0][2]=2*i+j; eledir[1][0]=4*i+j;
eledir[1][1]=3*i+j; eledir[1][2]=4*i+j;
eledir[2][0]=5*i+j; eledir[2][1]=6*i+j;
eledir[2][2]=7*i+j;
noddir[0][0]=2*i-2*j; noddir[0][1]=1*i-2*j;
noddir[0][2]=3*i-6*j; noddir[1][0]=4*i-5*j;
noddir[1][1]=5*i-2*j; noddir[1][2]=4*i-4*j;
noddir[2][0]=6*i-2*j; noddir[2][1]=7*i-2*j;
noddir[2][2]=8*i-3*j;
//-- Matrix multiplication ----
sum += mat_mul(eledir, noddir)/(sum+1);
}
}
return (int) sum;
}
OpenMP用于使用版本构建设置并行化此常规循环,并未显示相对于核心数的线性加速。
特别是,考虑到代码片段中的内部循环在串行执行中大约需要4毫秒。当外部环路在6个内核之间进行分区时,每个内部环路大约需要30毫秒,取消了通过并行化实现的加速,并使其比串行代码更慢。
比较调试版本的时间,我学会了30毫秒是执行未优化的内部循环的时间。因此,出于某种原因,优化不会在openMP并行化的情况下发生。你知道为什么会发生这样的事情,以及如何避免它?
代码示例简化并从非平凡代码中重现。
double mat_mul(double a[3][3], double b[3][3])
{
static double c[3][3];
c[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0];
c[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1];
c[0][2] = a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2];
c[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0];
c[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1];
c[1][2] = a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2];
c[2][0] = a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0];
c[2][1] = a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1];
c[2][2] = a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2];
return c[0][0]+c[0][1]+c[0][2]+c[1][0]+c[1][1]+c[1][2]+c[2][0]+c[2][1]+c[2][2];
}
发布版本中的优化标志:/ O2(最大化速度),/ Oi(启用内部函数),/ GL(整个程序优化),/ openmp以支持OpenMP,Visual C ++编译器,Windows 7。
更新:使用intel编译器(icc)时,这个问题不太明显。但是仍然不确定为什么在使用MSVC ++时会发生这种减速以及如何避免它。
UPDATE2:正如Mysticial指出的那样,问题是由mat_mul中的“static”关键字引起的。在使用OpenMP时,应谨慎对待静态变量。删除“static”关键字解决了这个问题。