Filter 可以为ARM NEON并行化过滤器吗?

Filter 可以为ARM NEON并行化过滤器吗?,filter,arm,simd,neon,Filter,Arm,Simd,Neon,我试图弄清楚一个特定的现有代码是否可以并行化,以及如何在ARM Cortex-A9 NEON SIMD单元中使用。代码如下: for(int i=0; i < 11; i++) { f4UF1 *= F[i]; A[i][2] = A[i][1]; A[i][1] = A[i][0]; A[i][0] = f4UF1; B[i][2] = B[i][1]; B[i][1] = B[i][0]; C[i] = 0; C[

我试图弄清楚一个特定的现有代码是否可以并行化,以及如何在ARM Cortex-A9 NEON SIMD单元中使用。代码如下:

for(int i=0; i < 11; i++)
{
    f4UF1 *= F[i];

    A[i][2] = A[i][1];
    A[i][1] = A[i][0];
    A[i][0] = f4UF1;

    B[i][2] = B[i][1];
    B[i][1] = B[i][0];

    C[i] = 0;

    C[i] += D[i][0] * A[i][0];
    C[i] += D[i][1] * A[i][1];
    C[i] += D[i][2] * A[i][2];

    C[i] -= E[i][1] * B[i][1];
    C[i] -= E[i][2] * B[i][2];

    B[i][0] = C[i] / E[i][0];

    f4UF1 = B[i][0];
}
for(int i=0;i<11;i++)
{
f4UF1*=F[i];
A[i][2]=A[i][1];
A[i][1]=A[i][0];
A[i][0]=f4UF1;
B[i][2]=B[i][1];
B[i][1]=B[i][0];
C[i]=0;
C[i]+=D[i][0]*A[i][0];
C[i]+=D[i][1]*A[i][1];
C[i]+=D[i][2]*A[i][2];
C[i]=E[i][1]*B[i][1];
C[i]=E[i][2]*B[i][2];
B[i][0]=C[i]/E[i][0];
f4UF1=B[i][0];
}

我已经看了相当多的代码了,我几乎可以肯定它不能被有效地并行化,但是我想,我可以试着在这里问一下。我并不期待现成的代码,只是关于如何做到这一点的想法。谢谢:)

是的,这看起来确实像是一个双四元组,每个样本的系数都会改变,可能是因为您正在平滑它们

正如一位评论者所提到的,您可能希望预先计算
1/E[i][0]
比例因子,并可能将其滚动到其他系数中以减少乘法的数量,特别是在浮点平台上。您还可以经常规范化双四元组,以消除
D[i][0]
(使其成为
1.0
),只需对整个输出应用标量

当然,您可能已经意识到,您希望在循环期间将所有内容都保存在寄存器中,然后在循环完成后才将它们写入内存…;-)

之后,我知道了两种矢量化技术(尽管我也对Nils的想法感兴趣):

  • 通道矢量化-最简单。如果需要同时对多个数据集应用过滤器(例如,立体声音频非常常见),则可以同时使用两组音频数据操作两组系数。我发现,如果您使用的是所有SP浮点,Neon为两个通道提供的寄存器数量刚好合适。即时2倍加速真的
  • 循环展开。这在这里有点难以详细描述,但幸运的是这里有一个很好的页面:。该技术添加极/零对,基本上一次计算更多样本。然而,额外的极点当然会为滤波器的稳定性增加额外的条件,因此必须小心。在您的例子中,当系数看起来是动态的时,这可能是某种需要确保的噩梦

  • 数据类型是什么?您应该粘贴能够满足编译器要求的内容。编译它并检查输出可能会提供一些见解。您可以使用vext指令向下滑动元素。您也可以进行乘法/加法运算。如果你用NEON写的话,看起来你可以把事情改进几个周期。唯一的问题是需要转换成乘法的除法。这是一个标准的双四元滤波器,对吗?好吧,如果你能接受一些全局输出延迟,那么有一些技巧可以并行化它。@Nilsippenbrinck:+1用于识别它的双四元组;不过,如果能为您提到的优化机会提供一些指导,那就太好了。