我正在尝试通过向量化此函数来提高this代码的性能:
inline float calcHaarPattern( const int* origin, const SurfHF* f, int n )
{
double d = 0;
for( int k = 0; k < n; k++ )
d += (origin[f[k].p0] + origin[f[k].p3] - origin[f[k].p1] - origin[f[k].p2])*f[k].w;
return (float)d;
}
据我所知,您可以对包含完全一个数学运算的循环进行矢量化。在上面的代码中,我们有5个数学运算,所以(使用OMP):
#pragma omp simd
for( int k = 0; k < n; k++ )
d += (origin[f[k].p0] + origin[f[k].p3] - origin[f[k].p1] - origin[f[k].p2])*f[k].w;
不会工作。但是,我在考虑是否将上面的循环分成多个循环而只进行一次数学运算是一个很好的矢量化实践?结果代码为:
double p0[n], p3[n], p1[n], p2[n];
#pragma omp simd
for( int k = 0; k < n; k++ )
p0[k] = origin[f[k].p0]*f[k].w;
#pragma omp simd
for( int k = 0; k < n; k++ )
p3[k] = origin[f[k].p3]*f[k].w;
#pragma omp simd
for( int k = 0; k < n; k++ )
p1[k] = origin[f[k].p1]*f[k].w;
#pragma omp simd
for( int k = 0; k < n; k++ )
p2[k] = origin[f[k].p2]*f[k].w;
#pragma omp simd
for( int k = 0; k < n; k++ )
d += p0[k];
#pragma omp simd
for( int k = 0; k < n; k++ )
d -= p1[k];
#pragma omp simd
for( int k = 0; k < n; k++ )
d -= p2[k];
#pragma omp simd
for( int k = 0; k < n; k++ )
d += p3[k];
这是一个很好的解决方案,还是有更好的解决方案?现代编译器(比如说gcc
)会自己做这种(或更好)的优化(例如启用-O3
)(所以实际上没有性能提升)?
答案 0 :(得分:1)
这通常是糟糕的HPC编程实践,原因如下:
循环分裂的理论优势也很少,但它们并不适用于您的情况,所以我提供它们以防万一。在以下情况下,循环拆分是合理的/有利可图的:
Intel Advisor(在前面的questons中提到过)有助于分析这些因素并测量AI。
良好的编制者也不会关心&#34;每当你有一个这样的循环或循环分裂时,因为它们可以轻松地将一个案例转换为另一个案例,反之亦然。 然而,在实际代码中,这种转换的适用性非常有限,因为为了做到这一点,你必须在编译时知道很多额外的信息:无论何时指针或动态数组重叠或不重叠,无论数据是否对齐所以你不应该依赖编译器转换和特定的编译器次要版本,而只需要尽可能多地编写HPC就绪代码。