NEON SIMD dotproduct在ARM Cortex A53上速度不快

NEON SIMD dotproduct在ARM Cortex A53上速度不快,arm,simd,neon,dot-product,Arm,Simd,Neon,Dot Product,我正在尝试实现一个需要计算某些数组的点积的应用程序。这需要非常快,所以我考虑用Neon测试SIMD。 我可以重写我的函数来使用SIMD,但是测量的时间几乎和以前一样,有时会多一点。 不使用SIMD时为31秒,使用SIMD时为32秒 以下是我的SIMD代码: float output = 0.0; for (int i=0; i<NUMBER_OF_INPUTS; i+=4) { in1_126 = vld1q_f32(&source

我正在尝试实现一个需要计算某些数组的点积的应用程序。这需要非常快,所以我考虑用Neon测试SIMD。 我可以重写我的函数来使用SIMD,但是测量的时间几乎和以前一样,有时会多一点。 不使用SIMD时为31秒,使用SIMD时为32秒

以下是我的SIMD代码:

        float output = 0.0;

    for (int i=0; i<NUMBER_OF_INPUTS; i+=4)
    {
        in1_126 = vld1q_f32(&source[i]);
        in2_126 = vld1q_f32(&weights[i]);
        out_126 = vmulq_f32(in1_126, in2_126);
        output +=  vaddvq_f32(out_126);
    }

    return output;  
但这并没有改变任何事情

为什么时间上几乎没有差别?还是说使用霓虹灯是让我的产品更快的错误方法?你还有什么其他的想法让它更快吗


谢谢你的回复

在循环中不应该从向量寄存器移动到标量寄存器

这将导致管道冲洗,每次冲洗大约需要14个周期。(在
ARMv7-A
上)

这些周期的数量取决于特定的体系结构

您可以尝试:

out126 = vmovq_n_f32(0.0f);
for (int i=0; i<NUMBER_OF_INPUTS; i+=4)
{
  in1_126 = vld1q_f32(&source[i]);
  in2_126 = vld1q_f32(&weights[i]);
  out_126 = vmlaq_f32(out_126, in1_126, in2_126);
}

output =  vaddvq_f32(out_126);
out126=vmovq_n_f32(0.0f);

对于(inti=0;i,在循环中不应该从向量寄存器移动到标量寄存器

它将导致管道刷新,每次发生时大约花费14个周期。(在
ARMv7-a
上)

这些周期的数量取决于特定的体系结构

您可以尝试:

out126 = vmovq_n_f32(0.0f);
for (int i=0; i<NUMBER_OF_INPUTS; i+=4)
{
  in1_126 = vld1q_f32(&source[i]);
  in2_126 = vld1q_f32(&weights[i]);
  out_126 = vmlaq_f32(out_126, in1_126, in2_126);
}

output =  vaddvq_f32(out_126);
out126=vmovq_n_f32(0.0f);

对于(int i=0;您是否检查了编译器是否已经对标量代码进行了矢量化?您是否也在使用
-O3
?我不知道如何检查,但可能是这样。我没有使用-O3,但现在我尝试使用它,它给出了相同的结果。使用
objdump
查看反汇编的输出,或者以交互方式播放。您是否检查了编译器是否已经对标量代码进行了矢量化?您是否也使用了
-O3
?我不知道如何检查,但可能是这样。我没有使用-O3,但现在我尝试使用它,它给出了相同的结果。使用
objdump
查看反汇编的输出,或以交互方式播放。谢谢!这就解决了问题,现在我的程序只需18秒就可以运行。@J.Ney 18秒还不够好。你应该尝试更深入地展开以隐藏延迟。如果性能至关重要,那么在汇编中编写是最后的唯一选择。谢谢!这就解决了问题,现在我的程序只需18秒就可以运行。@J.Ney 18秒还不够好。你知道吗如果性能至关重要,那么在汇编中编写是最终的唯一选择。
out126 = vmovq_n_f32(0.0f);
for (int i=0; i<NUMBER_OF_INPUTS; i+=4)
{
  in1_126 = vld1q_f32(&source[i]);
  in2_126 = vld1q_f32(&weights[i]);
  out_126 = vmlaq_f32(out_126, in1_126, in2_126);
}

output =  vaddvq_f32(out_126);