IOS/iPad/iPhone的最高速度

问题描述:

我使用OpenCViOS完成了计算密集型应用程序。当然这很慢。但它比我的PC原型慢200倍。所以我正在优化它。从最初的15秒开始,我能够获得0.4秒的速度。我想知道我是否找到了所有的东西以及其他人可能想要分享的内容。我所做的:IOS/iPad/iPhone的最高速度

  1. 替换成 “double” 数据类型里面的OpenCV为 “float”。 Double是64bit和32bit的CPU不能轻易处理它们,所以float给了我一些速度。 OpenCV经常使用double。

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

  3. 用90个值查找表替换sin()cos()实现。加速是巨大的!这与PC不同,这种优化不会加速。代码以度为单位工作,此值已转换为弧度为sin()cos()。此代码也被删除。但查找表完成了这项工作。

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

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

  6. 当然我用-O3 flag

  7. 我来自OpenCV的删除"dead code"。通常在优化OpenCV时,我会看到我的项目显然不需要的代码。例如,经常有额外的"if()"来检查像素大小为8位或32位,我知道我只需要8位。这会删除一些代码,为优化器提供更好的机会去除更多内容或用常量替换。此外,代码更适合缓存。

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

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

我也将解决你点一个接一个:

1)这是不是因为CPU的,这是因为随着ARMv7的时代只有32位浮点运算将在浮来计算的点处理器硬件(因为苹果取代了硬件)。而是用软件计算64位的。作为交换,32位操作速度更快。

2)NEON是设置

3)是,这是一个公知的方法中的新的浮点处理器指令的名称。另一种方法是使用我上面提到的Apple框架。它提供了可以并行计算4个值的正弦和余弦函数。该算法在组装和NEON中进行了精细调整,以便在使用最少电池时提供最佳性能。

4)拇指的新armv7实现没有armv6的缺点。禁用建议仅适用于v6。 5)是的,考虑到现在有80%的用户在iOS 5.0或更高版本(armv6设备在4.2.1结束支持),这在大多数情况下是完全可以接受的。

6)当您在发布模式下构建时,会自动发生这种情况。

7)是的,这不会有像上述方法一样大的影响。

我的建议是检查加速。这样,您可以确保充分利用浮点处理器的全部功能。

+0

这个加速度对我来说是新的。由于需要大会级别的思考,因此使用它仍然有点困难。但仍然有可能,也许会试一试。我稍后再接受它,因为我想看看我们是否能在这里获得更多有用的提示。 –

+1

在WWDC 2012视频中有一个会议完全处理Accelerate框架。你应该看看它^^ – borrrden

+0

http://adcdownload.apple.com//wwdc_2012/wwdc_2012_session_pdfs/session_708__the_accelerate_framework.pdf 和 https://developer.apple.com/videos/wwdc/2012/#708似乎作为它的链接 –

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

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

我想看看它是如何看待程序集。为了确保我可以用汇编找到它,我把它包这样的:

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

现在我按“产品 - >生成输出 - >大会文件”,我得到的是:

@ 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 

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

我也试图加快的建议与替代三行:

__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