1

下面的 C++ 代码片段展示了一个嵌套的 for循环,在内部层执行 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。

更新:使用英特尔编译器 (icc) 时,此问题不那么明显。但仍然不确定为什么在使用 MSVC++ 时会发生这种减速以及如何避免这种情况。

UPDATE2:正如 Mysticial 所指出的,这个问题是由 mat_mul 中的“static”关键字引起的。使用 OpenMP 时,应谨慎对待静态变量。删除“静态”关键字解决了这个问题。

4

0 回答 0