来自 IOS/iPad/iPhone 的最大速度

Posted

技术标签:

【中文标题】来自 IOS/iPad/iPhone 的最大速度【英文标题】:Maximum speed from IOS/iPad/iPhone 【发布时间】:2012-06-27 04:03:13 【问题描述】:

我使用OpenCVios 完成了计算密集型应用程序。当然,它很慢。但它比我的 PC 原型慢 200 倍。所以我正在优化它。从最初的 15 秒开始,我就可以达到 0.4 秒的速度。我想知道我是否找到了所有东西以及其他人可能想要分享的东西。我做了什么:

    将 OpenCV 中的“double”数据类型替换为“float”。 Double 是 64 位,而 32 位 CPU 无法轻松处理它们,所以 float 给了我一些速度。 OpenCV 经常使用 double。

    在编译器选项中添加了“-mpfu=neon”。副作用是模拟器编译器不再工作的新问题,任何东西都只能在本机硬件上测试。

    用 90 个值查找表替换了 sin()cos() 实现。加速是巨大的!这与 PC 有点相反,PC 的这种优化不会带来任何加速。有代码以度为单位工作,这个值被转换为sin()cos() 的弧度。这段代码也被删除了。但是查找表完成了这项工作。

    启用"thumb optimizations"。一些博客文章建议完全相反,但这是因为拇指在armv6 上通常会使事情变慢。 armv7 没有任何问题,让事情变得更快更小。

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

    我当然用-O3 flag

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

还有其他技巧和想法吗?对我来说,启用拇指并用查找替换三角函数是助推器,让我感到惊讶。也许您知道更多可以让应用飞起来的事情?

【问题讨论】:

【参考方案1】:

如果您要进行大量浮点计算,那么使用 Apple 的 Accelerate 框架会让您受益匪浅。它旨在使用浮点硬件对向量进行并行计算。

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

1) 这不是因为 CPU,而是因为从 armv7 时代开始,浮点处理器硬件中只会计算 32 位浮点运算(因为苹果更换了硬件)。 64 位的将改为在软件中计算。作为交换,32 位操作变得更快。

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

3) 是的,这是一种众所周知的方法。另一种方法是使用我上面提到的 Apple 框架。它提供了并行计算 4 个值的 sin 和 cos 函数。这些算法在组装和 NEON 中进行了微调,因此它们可以在使用最少电池的同时提供最佳性能。

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

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

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

7) 是的,不过效果不会像上面的方法那么大。

我的建议是查看 Accelerate。这样您就可以确保您充分利用了浮点处理器的全部功能。

【讨论】:

这个 Accelerate 对我来说是新的。它仍然有点难以使用,因为它需要汇编级别的思维。但仍有可能,也许会尝试一下。我稍后将其标记为已接受,因为我想看看我们是否在这里获得更多有用的提示。 WWDC 2012 视频中有一个会话完全涉及 Accelerate 框架。你应该看看它^^ adcdownload.apple.com//wwdc_2012/wwdc_2012_session_pdfs/… 和 developer.apple.com/videos/wwdc/2012/#708 似乎是它的链接【参考方案2】:

我对以前的帖子提供了一些反馈。这解释了我在第 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

很多代码。我打印出(int)(descriptors-&gt;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

【讨论】:

以上是关于来自 IOS/iPad/iPhone 的最大速度的主要内容,如果未能解决你的问题,请参考以下文章

iframe 内容未在 iOs5 iPad/iPhone 的滚动下呈现

使用 Python 最大化来自 Teensy 3.2 的实时绘图数据的串行通信速度

docker下使用disconf:极速体验

Origin橘子下载速度慢怎么办?2个满速下载方法

【U3D】Scene窗口移动速度过慢问题解决

excel版本越高VBA运行速度越慢,为啥?