英特尔 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】:

您在a1a2a2a3a3acc 以及acca1 之间存在数据依赖关系。这为您的循环每 4*(ADDPS 的延迟)周期执行一次循环迭代的速度设置了一个绝对下限 = 1 次循环迭代/12-16 个周期(具体数字取决于您的目标架构) .

像这样的依赖是矢量化的主要罪过。只是不要这样做。

相反,计算最初的四个向量,并在每次通过循环时将增量添加到每个向量的四倍。这样,它们就不会相互依赖,您的循环运行速度可以提高 3-4 倍。你可能仍然比vDSP_vramp 慢一些,因为你没有对对齐做任何特别的事情,你也没有在支持它的机器上利用 AVX,但这至少会让你进入正确的球场。

【讨论】:

以上是关于英特尔 SSE 的斜坡功能的主要内容,如果未能解决你的问题,请参考以下文章

使用英特尔 SSE 执行分支的最佳方式是啥?

使用快速英特尔随机生成器(SSE2)失败,堆栈周围...已损坏

如何将参数传递给英特尔 SSE 内在函数中的 const 值?

SSE3指令有啥功能?

not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

SSE 和超线程