ARM 程式設計優化策略與技術

2021-06-05 09:51:36 字數 4728 閱讀 1162

程式優化是指軟體程式設計結束後,利用軟體開發工具對程式進行調整和改進,讓程式充分利用資源, 提高執行效率, 縮減**尺寸的過程。按照優化的側重點不同, 程式優化可分為執行速度優化和**尺寸優化。執行速度優化是指在充分掌握軟硬體特性的基礎上, 通過

應用程式結構調整等手段來降低完成指定任務所需執行的指令數。在同乙個處理器上, 經過速度優化的程式比未經優化的程式在完成指定任務時所需的時間更短,即前者比後者具有更高的執行效率。**尺寸優化是指,採取措施使應用程式在能夠正確完成所需功能的前提下, 盡可能減少程式的**量。

然而在實際的程式設計過程中,程式優化的兩個目標(執行速度和**大小) 通常是互相矛盾的。為了提高程式執行效率,往往要以犧牲儲存空間、增加**量為代價, 例如程式設計中經常使用的以查表代替計算、迴圈展開等方法就容易導致程式**量增加。而為了減少程式**量、壓縮儲存器空間,可能又要以降低程式執行效率為代價。因此, 在對程式實施優化之前, 應先根據實際需求確定相應的策略。

在處理器資源緊張的情況下, 應著重考慮執行速度優化;而在儲存器資源使用受限的情況下, 則應優先考慮**尺寸的優化。

1 程式執行速度優化

程式執行速度優化的方法可分為以下幾大類。

1.1 通用的優化方法

(1)減小運算強度

(2)優化迴圈終止條件

在乙個迴圈結構中,迴圈的終止條件將嚴重影響著迴圈的效率,再加上arm 指令的條件執行特性,所以在

書寫迴圈的終止條件時應盡量使用count-down-to-zero結構

。這樣編譯器可以用一條bne (若非零則跳轉)指令代替cmp (比較)和ble (若小於則跳轉)兩條指令,既減小**尺寸,又加快了執行速度。

(3)使用inline 函式

arm c 支援 inline 關鍵字

,如果乙個函式被設計成乙個inline 函式,那麼在呼叫它的地方將會用函式體來替代函式呼叫語句, 這樣將會徹底省去函式呼叫的開銷。使用inline 的最大缺點是函式在被頻繁呼叫時,**量將增大。

1.2 處理器相關的優化方法

(1)保持流水線暢通

從前面的介紹可知,流水線延遲或阻斷會對處理器的效能造成影響,因此應該盡量保持流水線暢通。流水線延遲難以避免, 但可以利用延遲週期進行其它操作。

load/store 指令中的自動索引(auto-indexing)功能就是為利用流水線延遲週期而設計的。當流水線處於延遲週期時, 處理器的執行單元被占用, 算術邏輯單元(alu )和桶形移位器卻可能處於空閒狀態,此時可以利用它們來完成往基址暫存器上加乙個偏移量的操作,

供後面的指令使用。例如:指令 ldr r1, [r2], #4 完成 r1= *r2 及 r2 += 4 兩個操作,是後索引(post-indexing)的例子;而指令 ldr r1, [r2, #4]! 完成 r1 = *(r2 + 4) 和 r2 +=4 兩個操作,是前索引(pre-indexing)的例子。

流水線阻斷的情況可通過迴圈拆解等方法加以改善

。乙個迴圈可以考慮拆解以減小跳轉指令在迴圈指令中所佔的比重, 進而提高**效率。下面以乙個記憶體複製函式加以說明。

void memcopy(char *to, char *from, unsigned int nbytes)

為簡單起見,這裡假設nbytes 為16 的倍數(省略對餘數的處理)。上面的函式每處理乙個位元組就要進行一次判斷和跳轉, 對其中的迴圈體可作如下拆解:

void memcopy(char *to, char *from, unsigned int nbytes)

}這樣一來, 迴圈體中的指令數增加了,迴圈次數卻減少了。跳轉指令帶來的負面影響得以削弱。利用arm 7 處理器32 位字長的特性, 上述**可進一步作如下調整:

void memcopy(char *to, char *from, unsigned int nbytes)

}經過優化後

,一次迴圈可以處理16 個位元組(為什麼)

。跳轉指令帶來的影響進一步得到減弱。不過可以看出, 調整後的**在**量方面有所增加。

(2)使用暫存器變數 (如何)

cpu 對暫存器的訪問要比對記憶體的訪問快得多, 因此為變數分配乙個暫存器, 將有助於**的優化和執行效率的提高。整型、指標、浮點等型別的變數都可以分配暫存器; 乙個結構的部分或者全部也可以分配暫存器。給迴圈體中需要頻繁訪問的變數分配暫存器也能在

一定程度上提高程式效率。

1.3 指令集相關的優化方法

有時可以利用arm7 指令集的特點對程式進行優化。

(1)避免除法

arm 7 指令集中沒有除法指令,其除法是通過呼叫c 庫函式實現的。乙個32 位的除法通常需要20~140 個時鐘週期

。因此, 除法成了乙個程式效率的瓶頸, 應盡量避免使用。

有些除法可用乘法代替

,例如: if ( (x / y) > z)可變通為 if ( x > (y × z)) 。在能滿足精度,且儲存器空間

冗餘的情況下, 

也可考慮使用查表法代替除法

。當除數為2 的冪次方時, 應用

移位操作代替除法

。(2)利用條件執行

arm 指令集的乙個重要特徵就是所有的指令均可包含乙個可選的條件碼。當程式狀態暫存器(psr )中的條件碼標誌滿足指定條件時, 帶條件碼的指令才能執行。利用條件執行通常可以省去單獨的判斷指令,因而可以減小**尺寸並提高程式效率。

(3)使用合適的變數型別

arm 指令集支援有符號/ 無符號的8 位、16 位、32位整型及浮點型變數。恰當的使用變數的型別,不僅可以節省**,並且可以提高**執行效率。

應該盡可能地避免使用char、short 型的區域性變數,因為操作8 位/16 位區域性變數往往比操作3 2 位變數需要更多指令

, 請對比下列3 個函式和它們的彙編**。

intwordinc(inta) wordinc

shortinc

shortshortinc(shorta) add a1,a1,#1

mov pc,lr

charcharinc(chara) charinc

mov pc,lr

可以看出, 操作3 2 位變數所需的指令要少於操作8位及16 位變數。

1.4 儲存器相關的優化方法

(1)用查表代替計算

在處理器資源緊張而儲存器資源相對富裕的情況下, 可以用犧牲儲存空間換取執行速度的辦法。例如需要頻繁計算正弦或余弦函式值時,可預先將函式值計算出來置於記憶體中供以後查詢。

(2)充分利用片內ram

一些廠商出產的arm 晶元內整合有一定容量的ram,如atmel 公司的at91r40807 內有128kb 的ram,夏普公司的lh75400/lh75401 內有32kb 的ram。處理器對片內ram 的訪問速度要快於對外部ram 的訪問,所以應盡可能將程式調入片內ram 中執行。若因程式太大無法完全放入片內ram ,可考慮將使用最頻繁的資料或程式段調入片內ram 以提高程式執行效率。

1.5 編譯器相關的優化方法

多數編譯器都支援對程式速度和程式大小的優化,有些編譯器還允許使用者選擇可供優化的內容及優化的程度。相比前面的各種優化方法, 通過設定編譯器選項對程式進行優化不失為一種簡單有效的途徑。

2 **尺寸優化

精簡指令集計算機的乙個重要特點是指令長度固定, 這樣做可以簡化指令解碼的過程,但卻容易導致**尺寸增加。為避免這個問題,可以考慮採取以下措施來縮減程式**量。

2.1 使用多暫存器操作指令

arm 指令集中的多暫存器操作指令ldm/stm 可以載入/ 儲存多個暫存器,這在儲存/ 恢復暫存器組的狀態及進行大塊資料複製時非常有效。例如要將暫存器r4~r12 及r14 的內容儲存到堆疊中,若用str 指令共需要10 條,而一條stmea r13!, 指令就能達到相同的目的,節省的指令儲存空間相當可觀。不過需要注意的是, 雖然一條ldm/stm 指令能代替多條ldr/str 指令,但這並不意味著程式執行速度得到了提高。實際上處理器在執行ldm/stm 指令的時候還是將它拆分成多條單獨的ldr/str 指令來執行。

2.2 合理安排變數順序

arm 7 處理器要求程式中的32 位/16 位變數必須按字/ 半字對齊,這意味著如果變數順序安排不合理, 有可能會造成儲存空間的浪費。

例如:乙個結構體中的4個32 位int 型變數i1 ~ i4 和4 個8 位char 型變數c1 ~ c4,若按照i1、c1、i2、c2、i3、c3、i4、c4 的順序交錯存放時, 由於整型變數的對齊會導致位於2 個整型變數中間的那個8 位char 型變數實際占用32 位的儲存器,這樣就造成了儲存空間的浪費。為避免這種情況, 應將int 型變數和char 型變數按類似i1、i2、i3、i4、c1、c2、c3、c4 的順序連續存放。

2.3 使用thumb 指令

為了從根本上有效降低**尺寸,arm 公司開發了16 位的thumb 指令集。thumb 是arm 體系結構的擴充。thumb 指令集是大多數常用32 位arm 指令壓縮成16 位寬指令的集合。在執行時,16 位指令透明的實時解壓成32 位arm 指令並沒有效能損失。而且程式在thumb狀態和arm 狀態之間切換是零開銷的。與等價的32 位arm **相比,thumb **節省的儲存器空間可高達35% 以上。

結語綜上所述,優化的過程是在透徹了解軟/ 硬體結構和特性的前提下,充分利用硬體資源,不斷調整程式結構使之趨於合理的過程。其目的是最大程度發揮處理器效能,最大限度利用資源,盡可能提高程式在特定硬體平台上的效能。隨著arm 處理器在通訊及消費電子等行業中的應用日趨廣泛,優化技術將在基於arm 處理器的程式設計過程中發揮越來越重要的作用。

值得注意的是,程式的優化通常只是軟體設計需要達到的諸多目標之一, 優化應在不影響程式正確性、健壯性、可移植性及可維護性的前提下進行。

片面追求程式的優化往往會影響健壯性、可移植性等重要目標。

ARM程式設計優化方式

對區域性變數 函式引數和返回值要使用signed和unsigned int型別。這樣可以避免型別轉換,而且可高效地使用arm的32位資料操作指令。最高效的迴圈體形式是減計數到零 counts down to zero 的do while迴圈。展開重要的迴圈來減少迴圈的開銷。不要依賴編譯器來優化掉重複...

技術 技術方案優化策略 快取層面

兩種快取 什麼情況適合用快取?快取選型 什麼時候更新快取?如何保證更新的可靠性和實時性?更新快取的策略,需要具體問題具體分析。例如,目前約10萬個商品資料採用了redis作為快取服務,具體更新的策略有兩個 快取滿了怎麼辦?快取資料丟失怎麼辦?如果不允許,就需要帶持久化功能的快取服務來支援,比如red...

技術 技術方案優化策略 多執行緒與分布式

使用場景 離線任務 非同步任務 大資料任務 耗時較長任務的執行 適當地利用,可達到加速的效果。常用方案 1 單機多執行緒,可以引入執行緒池的機制,目標 2 多機多執行緒 分布式系統 引入乙個單獨的節點,作為排程器,其他的機器節點都作為執行器節點 排程器來負責拆分任務,和分發任務到合適的執行器節點 執...