【发布时间】:2014-03-28 19:55:57
【问题描述】:
我有代码要加快速度。首先,我使用了 SSE 内在函数并看到了显着的收益。我现在想看看我是否可以对 AVX 内在函数做类似的事情。本质上,该代码采用两个数组,根据需要对它们进行加减运算,将结果平方,然后将所有这些平方相加。
下面是使用 sse 内部函数的代码的简化版本:
float chiList[4] __attribute__((aligned(16)));
float chi = 0.0;
__m128 res;
__m128 nres;
__m128 del;
__m128 chiInter2;
__m128 chiInter;
while(runNum<boundary)
{
chiInter = _mm_setzero_ps();
for(int i=0; i<maxPts; i+=4)
{
//load the first batch of residuals and deltas
res = _mm_load_ps(resids+i);
del = _mm_load_ps(residDeltas[param]+i);
//subtract them
nres = _mm_sub_ps(res,del);
//load them back into memory
_mm_store_ps(resids+i,nres);
//square them and add them back to chi with the fused
//multiply and add instructions
chiInter = _mm_fmadd_ps(nres, nres, chiInter);
}
//add the 4 intermediate this way because testing
//shows it is faster than the commented out way below
//so chiInter2 has chiInter reversed
chiInter2 = _mm_shuffle_ps(chiInter,chiInter,_MM_SHUFFLE(0,1,2,3));
//add the two
_mm_store_ps(chiList,_mm_add_ps(chiInter,chiInter2));
//add again
chi=chiList[0]+chiList[1];
//now do stuff with the chi^2
//alternatively, the slow way
//_mm_store_ps(chiList,chiInter);
//chi=chiList[0]+chiList[1]+chiList[2]+chiList[3];
}
这让我想到了我的第一个问题:有什么方法可以更优雅地完成最后一点(我将 chiInter 中的 4 个浮点数相加并将它们加到一个浮点数中)? p>
无论如何,我现在正在尝试使用 avx 内在函数来实现这一点,这个过程的大部分过程都非常简单,不幸的是我正在拖延尝试做最后一点,试图将 8 个中间 chi 值压缩成一个值。
下面是 avx 内部函数的类似简化代码:
float chiList[8] __attribute__((aligned(32)));
__m256 res;
__m256 del;
__m256 nres;
__m256 chiInter;
while(runNum<boundary)
{
chiInter = _mm256_setzero_ps();
for(int i=0; i<maxPts; i+=8)
{
//load the first batch of residuals and deltas
res = _mm256_load_ps(resids+i);
del = _mm256_load_ps(residDeltas[param]+i);
//subtract them
nres = _mm256_sub_ps(res,del);
//load them back into memory
_mm256_store_ps(resids+i,nres);
//square them and add them back to chi with the fused
//multiply and add instructions
chiInter = _mm256_fmadd_ps(nres, nres, chiInter);
}
_mm256_store_ps(chiList,chiInter);
chi=chiList[0]+chiList[1]+chiList[2]+chiList[3]+
chiList[4]+chiList[5]+chiList[6]+chiList[7];
}
我的第二个问题是:有没有像我上面提到的 SSE 这样的方法可以让我更快地完成最后的添加?或者,如果有更好的方法来做我在 SSE 内在函数中所做的事情,它是否具有 AVX 内在函数的等价物?
【问题讨论】:
-
不要太担心最终总和的效率 - 假设
maxPts相当大,那么总时间将由 for 循环内发生的事情以及任何前导码/后置码控制代码将与性能无关。 -
@PaulR,不幸的是,maxPts 很小,通常不超过 32。是的,尽管尺寸很小,但我看到使用 sse 与 naive 循环的巨大收益,即 144ns / 迭代 --> 14ns / 迭代。
-
查看相关:stackoverflow.com/q/9775538/1918193。我很惊讶你没有尝试使用 haddps。要搜索的关键字:水平加法/总和。
-
@MarcGlisse,我没有,因为当我通过它时我不知道我在看什么。非常感谢您提供的信息。如果你把它写成答案,我很乐意接受。
-
如果 maxPts 很大,您可能需要检查
chi中最终累积误差平方的指数,浮点数(单精度浮点)只有 24 位有效位 en.wikipedia.org/wiki/Single-precision_floating-point_format 作为您的累积错误增加,您将失去精度,并且可能会达到停止进一步累积的程度(残差的中间平方增量可能比您运行累积的chi小 2^24 倍,并且当 CPU 归一化以添加它们时归零。