为什么设置LOCAL_ARM_NEON没有特殊代码路径的速度加倍?

时间:2015-08-28 15:32:12

标签: optimization assembly android-ndk arm neon

我正在使用Android上的NDK获取一些重型数字代码,使用LLVM工具链。

我发现如果我在Android.mk中设置LOCAL_ARM_NEON := true,我的代码速度几乎可以达到50%。我有编写任何NEON特定的源文件,并且在我的代码中没有NEON内在函数。这是否意味着编译器会自动将NEON指令注入其代码中?

如果是这种情况,那么因为这都是在编译器中生成的,所以我无法通过检查硬件支持来包装NEON代码路径。这里有最好的做法吗?或LOCAL_ARM_NEON := true从根本上说是不安全的?

进一步的细节:(需要注意的是,我对阅读ARM装配并不是很有经验)

生成的程序集的比较。

我发现这里较慢的组件非常易读。我发现更快的组装非常难以阅读。 我也不知道它是否有NEON特定指令,因为两个生成的文件似乎都有vmulthis page claims是NEON特定的指令 EDIT :显然vmul不是NEON特定的。

代码较慢(未设置LOCAL_ARM_NEON标志)

00000000 <_dotProduct>:
   0:   ed9f 0a08   vldr    s0, [pc, #32]   ; 24 <_dotProduct+0x24>
   4:   2a01        cmp r2, #1
   6:   bfb8        it  lt
   8:   4770        bxlt    lr
   a:   ed90 1a00   vldr    s2, [r0]
   e:   3004        adds    r0, #4
  10:   ed91 2a00   vldr    s4, [r1]
  14:   3104        adds    r1, #4
  16:   3a01        subs    r2, #1
  18:   ee22 1a01   vmul.f32    s2, s4, s2
  1c:   ee31 0a00   vadd.f32    s0, s2, s0
  20:   d1f3        bne.n   a <_dotProduct+0xa>
  22:   4770        bx  lr
  24:   00000000    .word   0x00000000

更快的代码(LOCAL_ARM_NEON := true

00000000 <_dotProduct>:
   0:   b510        push    {r4, lr}
   2:   2a01        cmp r2, #1
   4:   db1b        blt.n   3e <_dotProduct+0x3e>
   6:   2a00        cmp r2, #0
   8:   d01c        beq.n   44 <_dotProduct+0x44>
   a:   efc0 0050   vmov.i32    q8, #0  ; 0x00000000
   e:   f022 0c03   bic.w   ip, r2, #3
  12:   f1bc 0f00   cmp.w   ip, #0
  16:   d01a        beq.n   4e <_dotProduct+0x4e>
  18:   46e6        mov lr, ip
  1a:   460b        mov r3, r1
  1c:   4604        mov r4, r0
  1e:   f964 2a8f   vld1.32 {d18-d19}, [r4]
  22:   f1be 0e04   subs.w  lr, lr, #4
  26:   f104 0410   add.w   r4, r4, #16
  2a:   f963 4a8f   vld1.32 {d20-d21}, [r3]
  2e:   f103 0310   add.w   r3, r3, #16
  32:   ff44 2df2   vmul.f32    q9, q10, q9
  36:   ef42 0de0   vadd.f32    q8, q9, q8
  3a:   d1f0        bne.n   1e <_dotProduct+0x1e>
  3c:   e009        b.n 52 <_dotProduct+0x52>
  3e:   ef80 0010   vmov.i32    d0, #0  ; 0x00000000
  42:   bd10        pop {r4, pc}
  44:   ef80 0010   vmov.i32    d0, #0  ; 0x00000000
  48:   f04f 0c00   mov.w   ip, #0
  4c:   e00b        b.n 66 <_dotProduct+0x66>
  4e:   f04f 0c00   mov.w   ip, #0
  52:   eff0 28e0   vext.8  q9, q8, q8, #8
  56:   4594        cmp ip, r2
  58:   ef40 0de2   vadd.f32    q8, q8, q9
  5c:   fffc 2c60   vdup.32 q9, d16[1]
  60:   ef00 0de2   vadd.f32    q0, q8, q9
  64:   d011        beq.n   8a <_dotProduct+0x8a>
  66:   eb01 018c   add.w   r1, r1, ip, lsl #2
  6a:   eb00 008c   add.w   r0, r0, ip, lsl #2
  6e:   eba2 020c   sub.w   r2, r2, ip
  72:   ed90 2a00   vldr    s4, [r0]
  76:   3004        adds    r0, #4
  78:   ed91 3a00   vldr    s6, [r1]
  7c:   3104        adds    r1, #4
  7e:   3a01        subs    r2, #1
  80:   ff43 0d12   vmul.f32    d16, d3, d2
  84:   ef00 0d80   vadd.f32    d0, d16, d0
  88:   d1f3        bne.n   72 <_dotProduct+0x72>
  8a:   bd10        pop {r4, pc}

1 个答案:

答案 0 :(得分:0)

好的,我将根据@Michael和@Notlikethat的有用评论自己回答这个问题。那么,我的加速是因为NEON指令(当然)。

设置LOCAL_ARM_NEON := true似乎允许编译器生成NEON指令,即使对于非.neon文件也是如此。这将使代码不支持不支持NEON的ARMv7。

我认为这给了我两个选择,一个:使用和不使用LOCAL_ARM_NEON := true编译我的lib版本,并根据CPU是否支持NEON来决定加载哪个版本。

第二个是设置LOCAL_ARM_NEON := true,而是将我对性能敏感的代码路径复制到.c.neon文件中(只允许要使用NEON支持编译的文件。然后,在主文件中,使用cpufeatures lib检测NEON支持并切换到该文件(如果可用)。