2012-06-27 128 views
10

我使用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位。這會刪除一些代碼,爲優化器提供更好的機會去除更多內容或用常量替換。此外,代碼更適合緩存。

其他技巧和想法?對於我來說,啓用拇指和替換三角函數是助推器製造商,讓我感到驚訝。也許你知道要做更多的事情,這會讓應用程序飛行?

回答

13

如果您正在進行大量的浮點計算,那麼使用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似乎作爲它的鏈接 –

1

我對以前的帖子提供了一些反饋。這解釋了我在第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