IOS / iPad / iPhone的最高速度

我使用OpenCV for iOS完成了计算密集型应用程序。 当然这很慢。 但是这比我的电脑原型慢了200倍。 所以我正在优化它。 从最初的15秒开始,我能够获得0.4秒的速度。 我想知道我是否find了所有的东西,以及别人可能想要分享的东西。 我做了什么:

  1. 将OpenCV内的“ double ”数据typesreplace为“ float ”。 Double是64bit和32bit CPU不能轻易处理,所以float给了我一些速度。 OpenCV经常使用double。

  2. 编译器选项中增加了“ -mpfu=neon ”。 副作用是仿真器编译器不再工作的新问题,只能在本机硬件上testing任何东西。

  3. 使用90个值查找表replacesin()cos()实现。 加速是巨大的! 这与个人电脑有些相反,在这种情况下,这种优化不会加速。 代码以度为单位工作,这个值被转换为sin()cos()弧度。 这段代码也被删除了。 但查找表做了这项工作。

  4. 启用"thumb optimizations" 。 一些博客文章推荐完全相反,但这是因为拇指通常使armv6速度变慢。 armv7没有任何问题,使事情更快,更小。

  5. 为了确保拇指优化和-mfpu=neon工作在最好的状态,不要引入崩溃我完全删除armv6目标。 我所有的代码都编译为armv7 ,这也被列为app store的要求。 这意味着最低iPhone将是3GS 。 我认为放弃旧的是可以的。 无论如何,老一些的CPU速度较慢,CPU密集型应用程序如果安装在旧设备上,则会提供较差的用户体验

  6. 当然我使用-O3 flag

  7. 我从OpenCV中删除了"dead code" 。 通常在优化OpenCV时,我会看到我的项目显然不需要的代码。 例如经常有一个额外的"if()"来检查像素大小为8位或32位,我知道我只需要8位。 这将删除一些代码,为优化器提供更好的机会去除更多的东西或用常量replace。 另外代码更适合caching。

任何其他的技巧和想法? 对于我来说,启用拇指和replace三angular函数是助推器制造商,让我感到惊讶。 也许你知道更多的事情,使应用程序飞行?

如果你正在进行大量的浮点计算,那么使用Apple的Accelerate框架将会大大受益。 它旨在使用浮点硬件来并行计算vector。

我也会一一解答你的观点:

1)这不是因为CPU,这是因为在armv7时代,只有32位浮点运算会在浮点处理器硬件中计算(因为苹果已经replace了硬件)。 64位的将用软件来计算。 作为交换,32位操作得到了更快。

2)NEON是新的浮点处理器指令集的名称

3)是的,这是一个众所周知的方法。 另一种方法是使用上面提到的Apple框架。 它提供了并行计算4个值的正弦和余弦函数。 这些algorithm在组装和NEON中进行了精细调整,因此它们在使用最less的电池时提供最大的性能。

4)拇指的新的armv7实现没有armv6的缺点。 禁用build议仅适用于v6。

5)是的,考虑到现在有80%的用户在iOS 5.0或更高版本(armv6设备在4.2.1结束支持),这在大多数情况下是完全可以接受的。

6)当你在发布模式下构build时,会自动发生。

7)是的,这不会像上述方法那么大。

我的build议是检查加速。 这样你就可以确保你正在利用浮点处理器的全部function。

我对以前的post提供了一些反馈。 这解释了我在第7点提供的有关死代码的一些想法。这是为了稍微宽泛一些。 我需要格式化,所以不能使用任何评论forms。 这样的代码在OpenCV中:

 for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ ) { vec[kk] = 0; } 

我想看看它在组装上的样子。 为了确保我可以在assembly中find它,我将它包装成这样:

 __asm__("#start"); for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ ) { vec[kk] = 0; } __asm__("#stop"); 

现在我按“Product – > Generate Output – > Assembly file”,我得到的是:

  @ InlineAsm Start #start @ InlineAsm End Ltmp1915: ldr r0, [sp, #84] movs r1, #0 ldr r0, [r0, #16] ldr r0, [r0, #28] cmp r0, #4 mov r0, r4 blo LBB14_71 LBB14_70: Ltmp1916: ldr r3, [sp, #84] movs r2, #0 Ltmp1917: str r2, [r0], #4 adds r1, #1 Ltmp1918: Ltmp1919: ldr r2, [r3, #16] ldr r2, [r2, #28] lsrs r2, r2, #2 cmp r2, r1 bgt LBB14_70 LBB14_71: Ltmp1920: add.w r0, r4, #8 @ InlineAsm Start #stop @ InlineAsm End 

很多代码。 我的printf -d的值是(int)(descriptors->elem_size/sizeof(vec[0])) ,它总是64.所以我硬编码为64,再次通过汇编器传递:

  @ InlineAsm Start #start @ InlineAsm End Ltmp1915: vldr.32 s16, LCPI14_7 mov r0, r4 movs r1, #0 mov.w r2, #256 blx _memset @ InlineAsm Start #stop @ InlineAsm End 

正如你现在看到的,优化器得到了这个想法,代码变得更短了。 它能够对此进行vector化。 要点是编译器总是不知道什么input是常量,如果这是像摄像头的大小或像素深度,但实际上在我的情况下,他们通常是恒定的,我所关心的是速度。

我也尝试加速build议replace三行:

 __asm__("#start"); vDSP_vclr(vec,1,64); __asm__("#stop"); 

大会现在看起来:

  @ InlineAsm Start #start @ InlineAsm End Ltmp1917: str r1, [r7, #-140] Ltmp1459: Ltmp1918: movs r1, #1 movs r2, #64 blx _vDSP_vclr Ltmp1460: Ltmp1919: add.w r0, r4, #8 @ InlineAsm Start #stop @ InlineAsm End 

不确定这是否比bzero更快。 在我的情况下,这个部分没有太多时间,两个变种似乎以相同的速度工作。

我学到的另一件事是使用GPU。 更多关于它在这里http://www.sunsetlakesoftware.com/2012/02/12/introducing-gpuimage-framework