循环展开没有给出浮点点积的预期加速比 [英] loop unrolling not giving expected speedup for floating-point dot product
本文介绍了循环展开没有给出浮点点积的预期加速比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
/* Inner product. Accumulate in temporary */
void inner4(vec_ptr u, vec_ptr v, data_t *dest)
{
long i;
long length = vec_length(u);
data_t *udata = get_vec_start(u);
data_t *vdata = get_vec_start(v);
data_t sum = (data_t) 0;
for (i = 0; i < length; i++) {
sum = sum + udata[i] * vdata[i];
}
*dest = sum;
}
编写上述问题中描述的内积过程的一个版本
使用6x1a循环展开。对于x86-64,我们对展开版本的测量
对于整数数据,CPE为1.07,但对于两个浮点数据,CPE仍为3.01。
我的6*1a版本循环展开代码
void inner4(vec_ptr u, vec_ptr v, data_t *dest){
long i;
long length = vec_length(u);
data_t *udata = get_vec_start(u);
data_t *vdata = get_vec_start(v);
long limit = length -5;
data_t sum = (data_t) 0;
for(i=0; i<limit; i+=6){
sum = sum +
((udata[ i ] * vdata[ i ]
+ udata[ i+1 ] * vdata[ i+1 ])
+ (udata[ i+2 ] * vdata[ i+2 ]
+ udata[ i+3 ] * vdata[ i+3 ]))
+ ((udata[ i+4 ] * vdata[ i+4 ])
+ udata[ i+5 ] * vdata[ i+5 ]);
}
for (i = 0; i < length; i++) {
sum = sum + udata[i] * vdata[i];
}
*dest = sum;
}
问题:解释为什么在英特尔酷睿i7 Haswell处理器上运行的任何(标量)版本的内积程序都无法实现低于1.00的CPE。
您知道如何解决此问题吗?
推荐答案
您的展开无助于解决FP延迟瓶颈:
sum + x + y + z
没有-ffast-math
与sum += x;
的操作顺序相同...因此,您还没有对通过所有+
操作运行的单个依赖关系链做任何操作。循环开销(或前端吞吐量)不是的瓶颈,而是Haswell上addss
的3个周期延迟,所以这个展开基本上没有区别。
有效的方法是sum += u[i]*v[i] + u[i+1]*v[i+1] + ...
作为一种无需多个累加器的展开方式,因为这样每组元素的总和是独立的。
以这种方式进行的数学运算会稍微多一些,比如以mul开头,以Add结尾,但如果您用-march=haswell
编译,中间的运算仍然可以收缩为FMA。GCC将sum += u0*v0;
sum += u1*v1
天真的展开变成sum += u0*v0 + u1*v1;
的例子,见AVX performance slower for bitwise xor op and popcount的评论。在这种情况下,问题略有不同:sum += (u0-v0)**2 + (u1-v1)**2;
的平方差之和,但归结为最终进行一些乘法和加法的相同延迟问题。
addss
,因此单独进行sum += ...
添加,而不是作为FMA的一部分,实际上有助于解决Haswell的延迟瓶颈(与Skylake Add/Sub/MUL都是4个周期延迟不同)。以下所有内容都显示了使用多个累加器展开,而不是像您正在做的那样,使用第一个两两求和的方法将组加在一起:
- Why does mulss take only 3 cycles on Haswell, different from Agner's instruction tables? (Unrolling FP loops with multiple accumulators)
- When, if ever, is loop unrolling still useful?
- Loop unrolling to achieve maximum throughput with Ivy Bridge and Haswell
FP数学指令吞吐量不是现代CPU上大点产品的瓶颈,而是延迟。或加载吞吐量(如果展开足够多)。
解释为什么在英特尔酷睿i7 Haswell处理器上运行的任何(标量)版本的内积程序都无法实现低于1.00的CPE。
每个元素需要2个负载,并且只有2个负载端口,这是一个硬的吞吐量瓶颈。(https://agner.org/optimize//https://www.realworldtech.com/haswell-cpu/5/)
我假设您将一个";元素";计算为一个i
值,这是一对浮点数,分别来自udata[i]
和vdata[i]
。在Haswell上,FP FMA吞吐量瓶颈也是2/时钟(无论它们是标量、128位还是256位向量),但是点积在每个FMA上需要2个负载。从理论上讲,即使是沙桥,甚至K8也可以实现每个时钟1个元素,使用单独的mul和加法指令,因为它们都支持每个时钟2个加载,并且具有足够宽的流水线,以便通过流水线获得加载/muss/adds,并留出一些空闲空间。
这篇关于循环展开没有给出浮点点积的预期加速比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文