英特尔__assume的位置会影响性能

时间:2016-01-30 18:54:18

标签: c++ performance optimization vectorization intel

我正在使用如下所示的8阶有限差分时间步进函数(用于2D声波方程)。

与将其置于函数体的开头相比,我将内部循环中放置英特尔__assume语句的观察结果显着增加(高达25%)。 (无论OpenMP线程的数量如何,都会发生这种情况)。

代码由Intel 2016-update1编译器,Linux,-O3优化选项和支持AVX的架构(Xeon E5-2695 v2)编译。

这是编译器问题吗?

/* Finite difference, 8-th order scheme for acoustic 2D equation.
    p       - current pressure
    q       - previous and next pressure
    c       - velocity
    n0 x n1 - problem size
    p1      - stride
*/

void fdtd_2d( float const* const __restrict__ p,
              float      * const __restrict__ q,
              float const* const __restrict__ c,
              int          const              n0,
              int          const              n1,
              int          const              p1 )
{
    // Stencil coefficients.
    static const float C[5] = { -5.6944444e+0f, 1.6000000e+0f, -2.0000000e-1f, 2.5396825e-2f, -1.7857143e-3f };

    // INTEL OPTIMIZER PROBLEM?
    //     PLACING THE FOLLOWING LINE INSIDE THE LOOP BELOW 
    //     INSTEAD OF HERE SPEEDS UP THE CODE!
    // __assume( p1 % 16 == 0 );

    #pragma omp parallel for default(none)
    for ( int i1 = 0; i1 < n1; ++i1 )
    {
        float  const* const __restrict__ ps = p + i1 * p1;
        float       * const __restrict__ qs = q + i1 * p1;
        float  const* const __restrict__ cs = c + i1 * p1;

        #pragma omp simd aligned( ps, qs, cs : 64 )
        for ( int i0 = 0; i0 < n0; ++i0 )
        {
            // INTEL OPTIMIZER PROBLEM?
            //     PLACING THE FOLLOWING LINE HERE 
            //     INSTEAD OF THE ABOVE SPEEDS UP THE CODE!
            __assume( p1 % 16 == 0 );

            // Laplacian cross stencil:
            //   center and 4 points up, down, left and right from the center
            auto lap = C[0] * ps[i0];
            for ( int r = 1; r <= 4; ++r )
                lap += C[r] * ( ps[i0 + r] + ps[i0 - r] + ps[i0 + r * p1] + ps[i0 - r * p1] );

            qs[i0] = 2.0f * ps[i0] - qs[i0] + cs[i0] * lap;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我在英特尔网站上指出了以下内容:

  

__assume_aligned和__assume等子句告诉编译器该属性保存在子句出现的程序中的特定点。所以声明__assume_aligned(a,64);表示只要程序执行到达此点,指针a就会以64字节对齐。编译器可以将该属性传播到程序中的其他点(例如稍后的循环),但是这种行为不能得到保证(编译器可能必须做出保守的假设,并且不能安全地将属性应用于同一函数中的后续循环)。

因此,当我将__assume放在函数体的开头时,假设不会传播到内部循环中,从而导致代码效果不佳。

虽然,我的期望是合理的:因为p1被声明为const,编译器可能已经传播了这个假设。