轉載自: http://www.eeworld.com.cn/mcu/2012/0331/article_8260_2.html
代碼最佳化
代碼最佳化,就是採用組合語言或更精簡的程式碼來代替原有的代碼,使編譯後的程式運行效率更高。編譯器可以自動完成程式段和代碼區塊範圍內的最佳化,但很難擷取程式語義資訊、演算法流程和程式運行狀態資訊,因而需要編程人員進行手工最佳化。以下是一些常用的最佳化技術和技巧。
(1)代碼替換
使用周期短的指令代替周期長的指令,以降低運算的強度。
①減少除法運算。用關係運算子兩邊乘除數避免除法操作,還有一些除法和模數的運算可以用位操作來代替。因為位操作指令只需一個指令周期,而“/”運算則需要調用子程式,代碼長,執行慢。例如:
最佳化前if((a/b)>c)和a=a/4
最佳化後if(a>(b*c))和a=a>>2
②減少乘方運算。例如:
最佳化前a=pow(a,3.0)
最佳化後a=a*a*a
③使用白加、自減指令。例如:
最佳化前a=a+1、a=a-l
最佳化後a++、a--或inc、dec
④盡量使用小的資料類型。在所定義的變數滿足使用要求的條件下,優先使用順序為:字元型(char)>整型(im)>長整型(long int)>浮點型(float)。
對除法來說,使用無符號數比有符號數會有更高的效率。在實際調用中,盡量減少資料類型的強制轉換;少用浮點運算,如果運算的結果能夠控制在誤差之內,則可用長整型代替浮點型。
(2)全域變數與局部變數
少用全域變數,多用局部變數。全域變數是放在資料存放區器中的,定義了全域變數,MCU就少了一個可以利用的資料存放區器空間,太多的全域變數,會導致編譯器無足夠的記憶體配置;而局部變數則大多定位於MCU內部的寄存器中。在絕大多數的MCU中,使用寄存器的操作速度比資料存放區器快,指令也更靈活,有利於產生品質更高的代碼,而且局部變數所佔用的寄存器和資料存放區器在不同的模組中可以重複利用。
(3)使用寄存器變數
當一個變數被頻繁讀/寫時,需要反覆訪問記憶體,花費大量的存取時間。為了提高訪問效率,可以使用CPU寄存器變數,不需要訪問記憶體,直接進行讀/寫。迴圈次數較多的迴圈控制變數及迴圈體內反覆使用的變數均可定義為寄存器變數,而迴圈計數是應用寄存器變數的最佳選擇。只有局部自動變數和形參才可以定義為寄存器變數。因為寄存器變數屬於動態儲存裝置方式,因此凡需要採用靜態儲存方式的變數都不能定義為寄存器變數。寄存器變數的說明符是register。下面是一個採用寄存器變數的例子:
(4)減少或避免執行耗時的操作
應用程式的大量運行時問通常花費在關鍵程式模組,關鍵模組往往包含迴圈或嵌套迴圈。減少迴圈中耗時的操作,可以提高程式的執行速度。常見的耗時操作有:輸入/輸出操作、檔案訪問、圖形介面操作和系統調用等。其中,如果無法避免檔案的讀/寫,那麼對檔案的訪問將是影響程式運行速度的一大因素。提高檔案訪問速度的方法有兩種:一種是採用記憶體對應檔;另一種是使用記憶體緩衝。
(5)switch語句用法的最佳化
編程時,對case值按照可能性排序,將最可能發生的情況放在第一個,最不可能的情況放在最後一個,可以提高switch語句塊的執行速度。
(6)迴圈體的最佳化
迴圈體是程式設計和最佳化的重點,對於一些不需要迴圈變數參加運算的模組,可以把它放到迴圈的外面。對於次數固定的迴圈體,for迴圈比while迴圈效率更高,減計數迴圈比增計數迴圈速度快。例如:
實際運行時,每次迴圈需要在迴圈體外加兩條指令:一條減法指令(減少迴圈計數值)和一條條件分支指令。這些指令稱為“迴圈開銷”。在ARM處理器上,減法指令需要1個周期,條件分支指令需要3個周期,這樣每個迴圈另加了4個周期的開銷。可以採用迴圈展開的方法來提高迴圈啟動並執行速度,即:重複迴圈主題多次,並按同樣的比例減少迴圈次數來減小迴圈的開銷,以增加代碼尺寸。來換取程式的運行速度。。
(7)函數調用
高效的調用函數,盡量限制使用函數的參數個數,不要超過4個。ARM調用時,4個以下的形參通過寄存器傳遞,第5個以上的形參通過儲存空間棧傳遞。如果有更多的參數調用,則可將相關的參數組織在一個結構體內,用傳遞結構體指標來代替參數。
(8)內嵌函式和內嵌彙編
對效能影響大的重要函數可以使用關鍵字_inline內聯,會省去調用函數的開銷,負面影響是增加了代碼尺寸。程式中對時間要求苛刻的部分可以用內嵌彙編來編寫,通常可以帶來速度上的顯著提高。
(9)查表代替計算
在程式中盡量不進行非常複雜的運算,如浮點數的開方。對於這些消耗時間和資源的運算,可以採用空間換取時間的方法。預先將函數值計算出來,置於程式儲存區中,以後程式運行時直接查表即可,減小了程式執行過程中重複計算的工作量。
(10)使用針對硬體最佳化的函數庫
Intel公司為XScale處理器設計的GPP(Graphics Performance Primitives library)/IPP(Integrated Perform-ance Primitives library)庫,針對多媒體處理、圖形處理和數值運算的一些典型操作和演算法進行了手工最佳化,可以很好地發揮XScale硬體的計算潛能,達到很高的執行效率。
(11)利用硬體特性
為了提高程式的運行效率,要充分利用硬體特性來減小其運行開銷,例如減少中斷次數、利用DMA傳輸方式等。
CPU對各種儲存空間的訪問速度排序依次為:CPU內部RAM>外部同步RAM>外部非同步RAM>Flash/ROM。對於已經燒錄在 Flash或ROM中的程式碼,如果讓CPU直接從中讀取代碼執行,運行速度較慢,則可在系統啟動後將Flash或ROM中的目標代碼拷貝至RAM中後執行,以提高程式的運行速度。
4 結論
嵌入式程式的效能最佳化與軟體的開發週期、開發成本、軟體的可讀性之聞通常存在矛盾。要權衡利弊,作出折中的選擇。將演算法和資料結構最佳化作為首選最佳化技術;然後根據功能、效能差異和投資預算等因素選擇高效的編譯器、系統運行庫和圖形庫;使用效能監測工具偵測佔主要已耗用時間的程式熱點,採用代碼最佳化手段對其進行最佳化;最後使用高效的編譯器進行編譯最佳化,從而得到高品質的代碼。