- 相關推薦
嵌入式程序的優化
嵌入式程序的優化【1】
摘要:針對嵌入式系統的特點,介紹了幾種在嵌入式系統程序設計中優化C語言代碼的方法,從而提高系統的性能。
關鍵詞:C程序設計;程序優化;代碼優化
Abstract: According to the characteristics of embedded system, the paper introduced ways of C language code optimization in embedded system design so as enhance the performance of the system.
Key words: C program design; process optimization; code optimization
隨著數字信息技術和網絡技術高速發展嵌入式系統已經廣泛滲透到科學研究領域、各類產業和商業文化藝術以及人們的日常生活中,嵌入式計算機是完成某些特定功能的計算機系統,并且軟硬件可裁剪。
具有形態和性能更加小型化,多功能,低功耗等特點,已成為當今計算機技術發展的一個重要標志!
程序優化是指對解決同一問題的幾個不同的程序,進行比較、修改、調整或重新編寫程序,把一般程序變換為語句最少、占用內存量少、處理速度最快、外部設備分時使用效率最高的最優程序。
1嵌入式程序優化遵循的原則
嵌入式程序優化主要有以下3個原則:
、俚刃г瓌t:實現的功能需一致。
②有效原則:使得運行速度快或占用存儲空間小,或兼得。
③經濟原則:要付出較小的成本。
2嵌入式程序優化的主要實施方法
分別為:算法優化、編譯優化以及代碼優化。
2.1算法優化
選擇和構造適合于問題的算法;(冒泡排序還是快排的選擇問題是這一級早就應該完成的)很多經典算法都對問題作了一些假設(包括我們當前已經完成的算法實現),而在面對實際問題時我們應該重新檢視這些假設,并嘗試不同的思考問題的角度,尋求適合于問題的新算法;發掘問題的本來意義,從不同的角度思考面對的問題,使用適合于問題的的算法;嘗試打破一些規則,發掘和懷疑自己的某些假定,恢復問題的本來面目。
2.2編譯優化
目前很多編譯器都可實現代碼優化功能,且提供的代碼也很緊湊。
使用編譯器,能得到性能不錯的代碼。
然而,機器不能像人類那樣有創造性。
所以,我們還需要手工來做一些事情。
C語言代碼的優化是很難,且很需要技巧的工作。
大部分編譯器可以生成為處理器進行過特殊優化處理的代碼,如果進行修改,會造成特殊優化的破壞導致失效。
所以,在決定優化代碼之前,一定要測試一下,是自己的代碼更好還是編譯器生成的代碼好。
在嵌入式軟件開發過程中應挑選優化能力較強的編譯器,使其發揮代碼優化功能,來生成高效的代碼,提高程序的運行效率。
2.3代碼優化
1)變量的處理
編程過程中,解決初始化的問題,最好使用英文單詞的縮寫來代表變量。
用縮寫的好處可以加快程序的運行速度并減少占用的內存。
再一個就是變量類型的選取,選取的范圍越小也可以提高運行速度和降低內存的占有,不過算術運算時容易產生溢出。
函數調用越頻繁時,為提高代碼的效率,可以把聲明的局部變量通過編譯器放入寄存器中,而不是放入堆棧。
變量值很大,要使用變量作返回值,會很費時間。
使用參數作為返回值時間上會快些,因為沒有變量返回的復制時間的問題。
但安全性上和函數重復使用上差,因為參數返回破壞了參數值。
最好在編譯時,小的變量用指針返回,小的常量用變量返回,大的常量用參數或靜態方法返回。
還有就是使用全局變量比函數傳參數效率更高,不過要犧牲程序的重入和模塊化,它是因為節約了參數入棧和出棧的時間。
2)適當的使用宏
在嵌入式系統中,使用宏代替函數的方法來滿足性能要求,是在傳遞參數較多而函數較短的情況下不錯的選擇。
對宏的使用和定義需要謹慎,它可以實現類似函數的功能,又不像函數需要調用返回的好方法,它實質上并不是函數,需要考慮到展開后難以預料的結果。
如果宏的參數是復合結構,因為它只是簡單的替換,這里就要考慮操作符的優先級問題,單個參數內部各部分之間相互作用的操作符優先級低于各個參數之間的操作符優先級,在替換之后,我們需要括號保護宏參數,否則會產生預想不到的情形。
如果宏的參數是一個函數,展開時會對其參數多次取值,那么就有可能被調用多次從而達到不一致的結果,并有可能產生嚴重錯誤。
3)數組的處理
(1)數組在使用前需要對其先初始化。
數組的范圍在初始化時空著不添,在執行時將由數組自動加入,可以提高程序的運行速度。
由于事先定義的范圍可能過大,造成存儲的浪費。
(2)大部分情況下,數組索引用指針運算來替換,可以得到既快又短的代碼。
指針運算一般占用空間少,運行速度更快。
尤其是使用多維數組時效果更明顯。
一下是兩段作用相同,效率不同的代碼:
數組索引指針運算
for(;;){p=array
a=array[s++];for(;;){
……a=*(p++);
……
}}
指針方法的優點就是array的地址每次裝入地址p后,每次循環中,只需對p增量操作。
在數組索引方法中,每次循環中都必須進行基于s值求數組下標的復雜運算。
4)避免使用除法
ARM指令集沒有整數除法指令,通常除法指令由C語言庫中的函數執行。
對于不同的分子和分母,一個32位除法通常需要20至140個時鐘周期,執行除法函數的時間由一個固定時間加上每一位相除的時間。
由于除法操作較費時,所以應該避免使用除法。
我們知道,除法運算是乘法運算的逆運算,可通過改變表達式,把除法運算改成乘法運算。
因為無符號數除法的速度要高于有符號數的除法,如果其中有一個是無符號操作數最好使用無符號除法指令。
5)使用合適的數據類型
采用盡可能小的數據類型:可以用字符型定義的變量,就不要拿整型來定義,能拿整型定義的就不要拿長整型來定義,能不拿浮點型就不要拿浮點型來定義。
當然,一定要防止“溢出”現象,若超過變量的取值范圍后,系統并不會給出“出錯信息”,要靠我們的細心和經驗來確保結果的正確。
在確定表達式是float型和浮點型變量需注意:許多C編譯器把實型常量視為雙精度處理,降低了運算速度換來了更精確的結果,所以我們最好用“.F”、“.f”為后綴及在函數聲明時使用float型。
使用有符號整型變量時,要考慮是否有必要使用有符號的變量,一些情況下,有符號的運算比較快,但有時卻相反。
例如:把整型轉化為浮點型時,用大于16位的有符號整型比較快。
因為x86構架中沒有提供從無符號整型轉化到浮點型的指令,因為在整數運算中需計算商和余數,所以用無符號類型比較快。
6)使用寄存器變量
當一個變量被頻繁讀/寫時,要花費許多存取時間,反復訪問內存。
可以使用CPU寄存器變量來提高效率,它可以直接進行讀/寫,不需要訪問內存。
循環體內反復使用的變量和循環次數較多的循環控制變量都可定義為寄存器變量。
靜態存儲方式的變量都不能定義為寄存器變量,因為寄存器變量屬于動態存儲方式,所以只有局部自動變量和形參才可以定義為寄存器變量。
寄存器變量的說明符是register。
下面是一個采用寄存器變量的例子:
register i,sum=0;
for(i=1;i<=n;i++){
sum= sum+i;
…
}
7)If函數
在條件語句的判別中,先執行前面的判別,如果條件不滿足再執行后面的判斷。
最好將出現可能性最大的條件放在前面。
假如x數值為0-99中的任何一個數,并且概率相同。
if(x>10){ int x=11;}
else if(x<10){ int x=9;}
else (x==10){ int x=10;}
以上程序,當產生的x數值在10-99之間時(可能性最大),滿足第一個條件后計算機就直接從上述程序中返回而不再執行第二和第三個判別了,節省了運行的時間。
8)Switch語句中根據發生頻率來進行case排序
Switch語句是一個普通的編程技術,編譯器會產生if-else-if的嵌套代碼,并按照順序進行比較,發現匹配時,就跳轉到滿足條件的語句執行。
使用時要留意,每一個測試和跳轉只是為了決定下一步要做什么,很浪費處理時間。
為提高效率,可以把最可能發生的情況放在第一位,最不可能的情況放在最后。
9)使用布爾表達式
在C語言中,使用布爾表達式可以用來對變量是否在一定范圍內進行檢查。
例如布爾表達式x>=min&&x 3結論
嵌入式程序的性能優化與軟件的開發周期、開發成本、軟件的可讀性之間通常存在矛盾。
在編程時,應盡量優化自己的程序,減少不必要的運算,如果有多種編程方式可完成同一功能,應盡量選擇一種使程序最簡潔,高效的方法。
參考文獻:
[1]劉鋒,張曉林.淺析嵌入式程序設計中的優化問題[J].單片機與嵌入式系統應用,2006(12).
[2]王翠娥.淺析嵌入式C程序設計的優化[J].信息與電腦(理論版),2009(12).
[3]劉劍鳴.嵌入式程序設計中C/C++代碼的優化[J].微計算機信息,2003(12).
[4]金麗,包志華,陳海進.基于ARM嵌入式系統的C程序優化設計方法[J].南通大學學報:自然科學版,2006(3).
[5]曾振河.在ARM實時系統中提高程序執行的效率[J].漳州職業技術學院學報,2008(1).
[6]潭浩強.C程序設計[M].2版.北京:清華大學出版社,1999.
[7]陳波,石旭剛,史故臣.嵌入式C語言在系統開發中的代碼優化[J].計算機時代,2008(11).
[8]王軍安.淺析嵌入式系統的軟件優化設計[J].計算機工程與應用,2004(3).
[9]覃征,王志敏,王向華,等.程序設計方法與優化[M].西安:西安交通大學出版社,2004.
嵌入式程序設計中的優化問題【2】
嵌入式系統由于受功耗、成本和體積等因素的制約,嵌入式微處理器的處理能力與桌面系統處理器相比也存在較大差距,故嵌入式系統對程序運行的空間和時間要求更為苛刻。
通常,需要對嵌入式應用程序進行性能優化,以滿足嵌入式應用的性能需求。
1 嵌入式程序優化的類型
嵌入式應用程序優化,指在不改變程序功能的情況下,通過修改原來程序的算法、結構,并利用軟件開發工具對程序進行改進,使修改后的程序運行速度更高或代碼尺寸更小。
按照優化的側重點不同,程序優化可分為運行速度優化和代碼尺寸優化。
運行速度優化是指在充分掌握軟硬件特性的基礎上,通過應用程序結構調整等手段來縮短完成指定任務所需的運行時間;代碼尺寸優化則是指應用程序在能夠正確實現所需功能的前提下,盡可能減小程序的代碼量。
實際應用中,這兩者往往是相互矛盾的,為了提高程序運行速度,就要以增加代碼量為代價;而為了減小程序代碼尺寸,可能又要以降低程序運行速度為代價。
因此,在對程序進行優化之前,應根據實際需要來制定具體的優化策略。
隨著計算機和微電子技術的不斷發展,存儲空間已不再是制約嵌入式系統的主要因素,因此本文主要討論運行速度優化。
2 嵌入式程序優化遵循的原則
嵌入式程序優化主要遵循以下3個原則。
①等效原則:優化前后程序實現的功能一致。
②有效原則:優化后要比優化前運行速度快或占用存儲空間小,或二者兼有。
、劢洕瓌t:優化程序要付出較小的代價,取得較好的結果。
3 嵌入式程序優化的主要方面
嵌入式程序的優化分為3個方面:算法和數據結構優化、編譯優化以及代碼優化。
3.1 算法和數據結構優化
算法和數據結構是程序設計的核心所在,算法的好壞在很大程度上決定了程序的優劣。
為了實現某種功能,通?梢圆捎枚喾N算法,不同算法的復雜度和效率差別很大。
選擇一種高效的算法或對算法進行優化,可以使應用程序獲得更高的優化性能。
例如:在數據搜索時,二分查找法要比順序查找法快。
遞歸程序需要大量的過程調用,并在堆棧中保存所有返回過程的局部變量,時間效率和空間效率都非常低;若根據實際情況對遞歸程序采用迭代、堆棧等方法進行非遞歸轉換,則可大幅度提高程序的性能。
數據結構在程序的設計中也占有重要的地位。
例如:如果在一些無序的數據中多次進行插入、刪除數據項操作,那么采用鏈表結構就會比較快。
算法和數據結構優化是首選的優化技術。
3.2 編譯優化
現在,很多的編譯器都具有一定的代碼優化功能。
在編譯時,借用并行程序設計技術,進行相關性分析;獲得源程序的語義信息,采用軟件流水線、數據規劃、循環重構等技術,自動進行一些與處理器體系無關的優化,生成高質量的代碼。
許多編譯器有不同級別的優化選項,可以選用一種合適的優化方式。
通常情況下,如果選用了最高級別的優化方式,那么編譯器將片面追求代碼的優化,有時會導致錯誤。
另外,還有一些專用的編譯器針對某些體系結構進行了優化設計,可以充分利用硬件資源來生成高質量的代碼。
例如:Microsoft eMbedded Visual C++版的Intel編譯器完全針對Intel XScale體系,經過高度優化,能創建運行速度更快的代碼。
此編譯器采用了多種優化技術,包括優化指令管道操作的調度技術、雙重加載與存儲Intel XScale技術功能支持以及過程間優化(將函數使用的變量存放到寄存器,以便快速訪問)等。
在嵌入式軟件開發過程中應選擇一種優化能力強的編譯器,充分利用其代碼優化功能,生成高效的代碼,提高程序的運行效率。
3.3 代碼優化
代碼優化,就是采用匯編語言或更精簡的程序代碼來代替原有的代碼,使編譯后的程序運行效率更高。
編譯器可以自動完成程序段和代碼塊范圍內的優化,但很難獲取程序語義信息、算法流程和程序運行狀態信息,因而需要編程人員進行手工優化。
以下是一些常用的優化技術和技巧。
(1)代碼替換
使用周期短的指令代替周期長的指令,以降低運算的強度。
①減少除法運算。
用關系運算符兩邊乘除數避免除法操作,還有一些除法和取模的運算可以用位操作來代替。
因為位操作指令只需一個指令周期,而“/”運算則需要調用子程序,代碼長,執行慢。
例如:
優化前if((a/b)>c)和a=a/4
優化后if(a>(b*c))和a=a>>2
、跍p少乘方運算。
例如:
優化前a=pow(a,3.0)
優化后a=a*a*a
③使用白加、自減指令。
例如:
優化前a=a+1、a=a-l
優化后a++、a--或inc、dec
、鼙M量使用小的數據類型。
在所定義的變量滿足使用要求的條件下,優先使用順序為:字符型(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 結論
嵌入式程序的性能優化與軟件的開發周期、開發成本、軟件的可讀性之聞通常存在矛盾。
要權衡利弊,作出折中的選擇。
將算法和數據結構優化作為首選優化技術;然后根據功能、性能差異和投資預算等因素選擇高效的編譯器、系統運行庫和圖形庫;使用性能監測工具偵測占主要運行時間的程序熱點,采用代碼優化手段對其進行優化;最后使用高效的編譯器進行編譯優化,從而得到高質量的代碼。
【嵌入式程序的優化】相關文章:
優化排名原理,seo優化排名10-09
seo優化排名,seo優化教程10-09
嵌入式的實驗心得09-29
嵌入式系統設計10-07
嵌入式簡歷模板10-02
優化的方案04-09
優化方案02-07
優化關鍵詞-seo優化排名10-09
seo優化排名與關鍵詞優化10-09