我有代码,我正在努力加快.首先,我使用了SSE内在函数并获得了显着的收益.我现在正试图看看我是否可以用AVX内在函数做类似的事情.代码本质上需要两个数组,根据需要添加或减去它们,对结果进行平方,然后将所有这些方块加在一起.
下面是使用sse intrinsics的代码的简化版本:
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];
}
Run Code Online (Sandbox Code Playgroud)
这让我想到了第一个问题:有没有办法做最后一点(我将chiInter中的4个浮点数加到一个浮点数中)更优雅?
无论如何,我现在尝试使用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];
}
Run Code Online (Sandbox Code Playgroud)
我的第二个问题是:是否有一些方法,比如我用上面的SSE拉动,这将让我更快地完成最后的添加?或者,如果有更好的方法来做我在SSE内在函数中所做的事情,它是否具有AVX内在函数的等价物?
此操作称为水平和.说你有一个矢量v={x0,x1,x2,x3,x4,x5,x6,x7}.首先,提取高/低部分,以便你拥有w1={x0,x1,x2,x3}和w2={x4,x5,x6,x7}.现在打电话_mm_hadd_ps(w1, w2)给:tmp1={x0+x1,x2+x3,x4+x5,x6+x7}.再次,_mm_hadd_ps(tmp1,tmp1)给人tmp2={x0+x1+x2+x3,x4+x5+x6+x7,...}.最后一次,_mm_hadd_ps(tmp2,tmp2)给出tmp3={x0+x1+x2+x3+x4+x5+x6+x7,...}.您也可以用_mm_hadd_ps简单的替换第一个_mm_add_ps.
这些都是未经测试并从文档中编写的.对速度也没有承诺......
英特尔论坛上有人展示了另一种变体(寻找HsumAvxFlt).
我们还可以通过编译此代码来查看gcc建议的内容 gcc test.c -Ofast -mavx2 -S
float f(float*t){
t=(float*)__builtin_assume_aligned(t,32);
float r=0;
for(int i=0;i<8;i++)
r+=t[i];
return r;
}
Run Code Online (Sandbox Code Playgroud)
生成的test.s包含:
vhaddps %ymm0, %ymm0, %ymm0
vhaddps %ymm0, %ymm0, %ymm1
vperm2f128 $1, %ymm1, %ymm1, %ymm0
vaddps %ymm1, %ymm0, %ymm0
Run Code Online (Sandbox Code Playgroud)
最后一条指令没有让我感到有些惊讶vaddss,但我想这并不重要.
| 归档时间: |
|
| 查看次数: |
1135 次 |
| 最近记录: |