英特尔 SSE 的斜坡功能
Posted
技术标签:
【中文标题】英特尔 SSE 的斜坡功能【英文标题】:Ramp function for Intel SSE 【发布时间】:2015-04-07 18:09:21 【问题描述】:我正在将我的 OsX DSP 库移植到 Windows。从 vDSP_ramp 开始,它被大量使用。此函数生成一个递增值 C[i] = C[i-1] + A 的斜坡。
这是我使用内在函数的 SSE 版本(我将增量向量添加到累加器并存储)
__m128 acc = A[0],A[0]+(*B),A[0]+2*(*B), A[0]+3*(*B);//_mm_set1_ps(0.0);
float i1 = 4*(*B);
__m128 inc = i1,i1,i1,i1;
int ln = N/4/4;
for(int i=0; i<ln; i++)
__m128 a1 = _mm_add_ps(acc, inc);
__m128 a2 = _mm_add_ps(a1, inc);
__m128 a3 = _mm_add_ps(a2, inc);
acc = _mm_add_ps(a3, inc);
_mm_store_ps(C, a1);
_mm_store_ps(C+4, a2);
_mm_store_ps(C+8, a3);
_mm_store_ps(C+12, acc);
C+=16;
我什至展开了循环,但它仍然比原来的 vdsp_ramp 函数多花 5 倍的时间。
如何进一步优化?这里有什么问题?
Edit1:参考代码:
void BSDSP_vramp(
const float *A,
const float *B,
float *C,
unsigned long N)
for(int i=0; i<N; i++)
C[i] = (*A)+i*(*B);
【问题讨论】:
依赖与乘法? 原码是什么?您的新代码的 MCVE (***.com/help/mcve) 是什么?您在哪些平台上运行它们?你是如何衡量执行时间的? 参考代码添加到原帖。使用 Instruments 时间分析器在 XCode 下使用 LLVM 编译。我从一个 _mm_add_ps 和 _mm_store_ps 开始。这太糟糕了,我决定稍微展开循环,确实有点帮助:) 【参考方案1】:您在a1
和a2
、a2
和a3
、a3
和acc
以及acc
和a1
之间存在数据依赖关系。这为您的循环每 4*(ADDPS
的延迟)周期执行一次循环迭代的速度设置了一个绝对下限 = 1 次循环迭代/12-16 个周期(具体数字取决于您的目标架构) .
像这样的依赖是矢量化的主要罪过。只是不要这样做。
相反,计算最初的四个向量,并在每次通过循环时将增量添加到每个向量的四倍。这样,它们就不会相互依赖,您的循环运行速度可以提高 3-4 倍。你可能仍然比vDSP_vramp
慢一些,因为你没有对对齐做任何特别的事情,你也没有在支持它的机器上利用 AVX,但这至少会让你进入正确的球场。
【讨论】:
以上是关于英特尔 SSE 的斜坡功能的主要内容,如果未能解决你的问题,请参考以下文章
使用快速英特尔随机生成器(SSE2)失败,堆栈周围...已损坏
如何将参数传递给英特尔 SSE 内在函数中的 const 值?