assembly - NEON ASM 代码运行速度比 C 代码慢很多?

标签 assembly arm neon

我正在尝试使用 NEON 在 iPhone ARM 上针对特定问题实现高斯牛顿优化。下面的第一个函数是我原来的 C 函数。第二个是我写的NEON asm代码。我每个都运行了 100,000 次,NEON 版本比 C 版本花费了 7-8 倍的时间。我认为加载(vld1.32)是花费大部分时间的。我尝试删除一些指令。

有人对这个问题有任何见解吗?谢谢!

template<class T>
inline void GaussNewtonOperationJtr8x8(T Jtr[8], const T J[8], T residual)
{
    Jtr[0] -= J[0]*residual;
    Jtr[1] -= J[1]*residual;
    Jtr[2] -= J[2]*residual;
    Jtr[3] -= J[3]*residual;
    Jtr[4] -= J[4]*residual;
    Jtr[5] -= J[5]*residual;
    Jtr[6] -= J[6]*residual;
    Jtr[7] -= J[7]*residual;    
}

inline void GaussNewtonOperationJtr8x8_NEON(NFloat Jtr[8], const NFloat J[8], NFloat residual)
{
    __asm__ volatile (
                      // load Jtr into registers
                      "vld1.32   {d0-d3}, [%0]\n\t"
                      // load J into registers
                      "vld1.32   {d4-d7}, [%1]\n\t"
                      // load residual in register
                      "vmov.f32  s16, %2\n\t"
                      // Jtr -= J*residual
                      "vmls.f32  q0, q2, d8[0]\n\t"
                      "vmls.f32  q1, q3, d8[0]\n\t"
                      // store result
                      "vst1.32   {d0-d3}, [%0]\n\t"
                      // output
                      :
                      // input
                      : "r"(Jtr), "r"(J), "r"(residual)
                      // registers
                      : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14"
                      );
}

最佳答案

  1. 不要使用 d8-d15。在使用之前必须将它们保存到堆栈中。并于事后恢复。编译器将放置指令来执行此操作,从而浪费宝贵的周期。
  2. 在 Jtr 之前加载 J。 Jtr 预计处于比 J 晚的管道阶段。
  3. 使用 VLDMIA/VSTMIA 而不是 VLD/VST。 VLDMIA/VSTMIA 速度更快,并且在管道方面具有优势。
  4. 使用向量-向量乘法而不是向量-标量乘法。
  5. 如果您创建循环版本,请将 pld 放在开头并展开循环,以便每次迭代从每个指针读取 64 个字节。

除了我上面提到的那些错误 - 这对于 NEON 新手来说是典型的 - 你的方法非常好。您在 vmls 中找到了最合适的指令。

干得好。

{

__asm__ volatile (
    // load residual in register
    "vdup.32  q12, %2\n\t"
    // load J into registers
    "vldmia   %1, {q10-q11}\n\t"
     // load Jtr into registers
    "vldmia   %0, {q8-q9}\n\t"
    // Jtr -= J*residual
    "vmls.f32  q8, q10, q12\n\t"
    "vmls.f32  q9, q11, q12\n\t"
    // store result
    "vstmia   %0, {q8-q9}\n\t"
    // output
    :
    // input
    : "r"(Jtr), "r"(J), "r"(residual)
    // registers
    : "q8", "q9", "q10", "q11", "q12"
);

关于assembly - NEON ASM 代码运行速度比 C 代码慢很多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6034966/

相关文章:

assembly - 使用 NEON 优化 Cortex-A8 颜色转换

linux - 从可执行文件中删除所有符号表和重定位信息的影响?

assembly - REP MOVSB 用于重叠内存

assembly - 关于 ARM 指令时机

arm - 语法错误 : word unexpected (expecting ")")

c++ - Windows RT on ARM native 代码调用约定是什么?

optimization - ARM NEON : How to implement a 256bytes Look Up table

c++ - 必须有一种非常快速的方法来计算这个按位表达式吗?

assembly - 为什么我们要使用addiu而不是addi?

macos - 如何从 Mac OS X 调试 ARM