我正在使用如下所示的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;
}
}
}
答案 0 :(得分:2)
我在英特尔网站上指出了以下内容:
__assume_aligned和__assume等子句告诉编译器该属性保存在子句出现的程序中的特定点。所以声明__assume_aligned(a,64);表示只要程序执行到达此点,指针a就会以64字节对齐。编译器可以将该属性传播到程序中的其他点(例如稍后的循环),但是这种行为不能得到保证(编译器可能必须做出保守的假设,并且不能安全地将属性应用于同一函数中的后续循环)。
因此,当我将__assume
放在函数体的开头时,假设不会传播到内部循环中,从而导致代码效果不佳。
虽然,我的期望是合理的:因为p1
被声明为const
,编译器可能已经传播了这个假设。