- 相關(guān)推薦
嵌入式系統(tǒng)編程中的代碼優(yōu)化
今天,嵌入式系統(tǒng)已經(jīng)廣泛地應(yīng)用于工業(yè)控制、信息家電、辦公自動(dòng)化、移動(dòng)通信、儀器儀表、醫(yī)療電子以及國(guó)防等領(lǐng)域。隨著國(guó)內(nèi)外各種嵌入式產(chǎn)品的進(jìn)一步開發(fā)和推廣,嵌入式技術(shù)越來越和人們的生活緊密結(jié)合。那么嵌入式系統(tǒng)編程中的代碼如何優(yōu)化,下面跟yjbys小編一起來學(xué)習(xí)一下。
1 引言
嵌入式系統(tǒng)一般指非PC系統(tǒng),通常完成一種或多種特定的計(jì)算機(jī)功能。它是以應(yīng)用為中心,軟硬件可裁減的,適應(yīng)應(yīng)用系統(tǒng)對(duì)功能,可靠性,成本,體積,功耗等綜合性要求的專用計(jì)算機(jī)系統(tǒng)。簡(jiǎn)單的說類似于PC中的BIOS的工作方式,具有軟件代碼小、高度自動(dòng)化、響應(yīng)速度快等特點(diǎn)。特別適合于要求實(shí)時(shí)和多任務(wù)的應(yīng)用體系。嵌入式實(shí)時(shí)系統(tǒng)是目前蓬勃發(fā)展的行業(yè)之一。但是,實(shí)時(shí)嵌入式系統(tǒng)的特點(diǎn)使得其軟件受時(shí)間和空間的嚴(yán)格限制,加上運(yùn)行環(huán)境復(fù)雜,使得嵌入式系統(tǒng)軟件的開發(fā)變得異常困難。 為了設(shè)計(jì)一個(gè)滿足功能、性能和時(shí)間要求的安全可靠的高性能嵌入式系統(tǒng),編程語言的選擇十分重要。
2 嵌入式系統(tǒng)中編程語言的選擇
因?yàn)閰R編語言編寫的代碼難懂,從而不好維護(hù)和難于調(diào)試,且只能針對(duì)特定的體系結(jié)構(gòu)和處理器移植性差,所以既不宜在復(fù)雜系統(tǒng)中使用,又不便于實(shí)現(xiàn)軟件重用;而高級(jí)語言具有良好的通用性和豐富的軟件支持,可移植性好、易于維護(hù),因此高級(jí)語言編程具有許多優(yōu)勢(shì)。隨著嵌入式系統(tǒng)應(yīng)用范圍的不斷擴(kuò)大和嵌入式實(shí)時(shí)操作系統(tǒng)RTOS(Real Time Operating System)的廣泛使用,高級(jí)語言編程已是嵌入式系統(tǒng)設(shè)計(jì)的必然趨勢(shì)。但是不排除一些軟件模塊仍用匯編語言來寫,這可以使程序更加有效。雖然C/C++編譯器對(duì)代碼進(jìn)行了優(yōu)化,但是適當(dāng)?shù)氖褂脙?nèi)聯(lián)匯編指令可以有效的提高整個(gè)系統(tǒng)運(yùn)行的效率。目前,在嵌入式系統(tǒng)開發(fā)過程中使用的語言種類很多,但僅有少數(shù)幾種語言得到了比較廣泛的應(yīng)用。其中C和C++是應(yīng)用最廣泛的。C++在支持現(xiàn)代軟件工程、 OOP(Object Oriented Programming,面向?qū)ο蟮某绦蛟O(shè)計(jì))、結(jié)構(gòu)化等方面對(duì)C進(jìn)行了卓有成效的改進(jìn),但在程序代碼容量、執(zhí)行速度、程序復(fù)雜程度等方面比C語言程序性能差一些。由于C語言既有低級(jí)語言的直接控制硬件的能力,又有高級(jí)語言的靈活性,是目前在嵌入式系統(tǒng)中應(yīng)用最廣泛的編程語言。隨著網(wǎng)絡(luò)技術(shù)和嵌入式技術(shù)的不斷發(fā)展,Java的應(yīng)用也得到廣泛應(yīng)用。
3 實(shí)時(shí)程序設(shè)計(jì)中代碼的優(yōu)化
在嵌入式的系統(tǒng)開發(fā)中,出于對(duì)低價(jià)產(chǎn)品的需求, 硬件的設(shè)計(jì)者需要提供剛好足夠的存儲(chǔ)器和完成工作的處理能力。所以在嵌入式軟件設(shè)計(jì)的最后一個(gè)階段則變成了對(duì)代碼的優(yōu)化。
代碼優(yōu)化的目標(biāo)是體積小和速度快,可以從算法、數(shù)據(jù)和指令流三方面來考慮。
3.1 算法優(yōu)化
大多數(shù)情況下,速度同內(nèi)存(或者是性能,比如說壓縮性能)是不可兼得的。目前程序加速的常用算法一個(gè)大方面就是利用查表來避免計(jì)算(比如在jpg有 huffman碼表,在YUV到RGB變換也有變換表)這樣原來的復(fù)雜計(jì)算現(xiàn)在僅僅查表就可以了,雖然浪費(fèi)了內(nèi)存,不過速度顯著提升。此外在編寫程序時(shí)還要注意提高效率,例如:
3.1.1Switch語句中根據(jù)發(fā)生頻率來進(jìn)行case排序
switch語句是一個(gè)普通的編程技術(shù),編譯器會(huì)產(chǎn)生if-else-if的嵌套代碼,并按照順序進(jìn)行比較,發(fā)現(xiàn)匹配時(shí),就跳轉(zhuǎn)到滿足條件的語句執(zhí)行。使用時(shí)需要注意。每一個(gè)由機(jī)器語言實(shí)現(xiàn)的測(cè)試和跳轉(zhuǎn)僅僅是為了決定下一步要做什么,就把寶貴的處理器時(shí)間耗盡。為了提高速度,設(shè)法根據(jù)具體的情況按照它們發(fā)生的相對(duì)頻率排序。換句話說,把最可能發(fā)生的情況放在第一位,最不可能的情況放在最后。
3.1.2將大的switch語句轉(zhuǎn)為嵌套switch語句
當(dāng)switch語句中的case標(biāo)號(hào)很多時(shí),為了減少比較的次數(shù),明智的做法是把大switch語句轉(zhuǎn)為嵌套switch語句。把發(fā)生頻率高的case 標(biāo)號(hào)放在一個(gè)switch語句中,并且是嵌套switch語句的最外層,發(fā)生相對(duì)頻率相對(duì)低的case標(biāo)號(hào)放在另一個(gè)switch語句中。如果switch中每一種情況下都有很多的工作要做,那么把整個(gè)switch語句用一個(gè)指向函數(shù)指針的表來替換會(huì)更加有效。
3.1.3用指針代替數(shù)組
在許多種情況下,可以用指針運(yùn)算代替數(shù)組索引,這樣做常常能產(chǎn)生又快又短的代碼。與數(shù)組索引相比,指針一般能使代碼速度更快,占用空間更少。使用多維數(shù)組時(shí)差異更明顯。下面的代碼作用是相同的,但是效率不一樣。
數(shù)組索引 指針運(yùn)算
For(;;){ p=array
A=array[r++]; for(;;){
a=*(p++);
...... ......
} }
指針方法的優(yōu)點(diǎn)是,array的地址每次裝入地址p后,在每次循環(huán)中只需對(duì)p增量操作。在數(shù)組索引方法中,每次循環(huán)中都必須進(jìn)行基于r值求數(shù)組下標(biāo)的復(fù)雜運(yùn)算。
3.1.4使用宏函數(shù)而不是函數(shù)。例如:
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)
#define BIT_MASK(__bf) (((1U << (bw ## __bf)) - 1) << (bs ## __bf))
#define SET_BITS(__dst, __bf, __val) ((__dst) = ((__dst) & ~(BIT_MASK(__bf))) | (((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))
SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);
函數(shù)和宏函數(shù)的區(qū)別就在于,宏函數(shù)占用了大量的空間,而函數(shù)占用了時(shí)間。函數(shù)調(diào)用是要使用系統(tǒng)的棧來保存數(shù)據(jù)的,如果編譯器里有棧檢查選項(xiàng),一般在函數(shù)的頭會(huì)嵌入一些匯編語句對(duì)當(dāng)前棧進(jìn)行檢查;同時(shí),CPU也要在函數(shù)調(diào)用時(shí)保存和恢復(fù)當(dāng)前的現(xiàn)場(chǎng),進(jìn)行壓棧和彈棧操作,所以,函數(shù)調(diào)用需要一些CPU時(shí)間。而宏函數(shù)不存在這個(gè)問題。宏函數(shù)僅僅作為預(yù)先寫好的代碼嵌入到當(dāng)前程序,不會(huì)產(chǎn)生函數(shù)調(diào)用,所以僅僅是占用了空間,在頻繁調(diào)用同一個(gè)宏函數(shù)的時(shí)候,該現(xiàn)象尤其突出。
3.2 Data optimization數(shù)據(jù)優(yōu)化
比算法優(yōu)化層低一級(jí)的是數(shù)據(jù)優(yōu)化層,我們可以通過改變算法使用的數(shù)據(jù)類型來優(yōu)化算法。主要的目的是使處理的數(shù)據(jù)和目標(biāo)結(jié)構(gòu)的特性相一致。這項(xiàng)優(yōu)化不需要大量的代碼重寫,并獨(dú)立于算法優(yōu)化的執(zhí)行而執(zhí)行.例如:
3.2.1確定浮點(diǎn)型變量和表達(dá)式是 float 型
為了讓編譯器產(chǎn)生更好的代碼,必須確定浮點(diǎn)型變量和表達(dá)式是 float 型的。要特別注意的是,以 ";F"; 或 ";f";為后綴(比如:2.718f)的浮點(diǎn)常量才是 float 型,否則默認(rèn)是 double 型。為了避免 float 型參數(shù)自動(dòng)轉(zhuǎn)化為 double,請(qǐng)?jiān)诤瘮?shù)聲明時(shí)使用 float。
3.2.2使用32位的數(shù)據(jù)類型
編譯器有很多種,但它們都包含的典型的32位類型是:int,signed,signed int,unsigned,unsigned int,long,signed long,long int,signed long int,unsigned long,unsigned long int。盡量使用32位的數(shù)據(jù)類型,因?yàn)樗鼈儽?6位的數(shù)據(jù)甚至8位的數(shù)據(jù)更有效率。
3.2.3明智使用有符號(hào)整型變量
在很多情況下,你需要考慮整型變量是有符號(hào)還是無符號(hào)類型的。在許多地方,考慮是否使用有符號(hào)的變量是必要的。在一些情況下,有符號(hào)的運(yùn)算比較快;但在一些情況下卻相反。比如:整型到浮點(diǎn)轉(zhuǎn)化時(shí),使用大于16位的有符號(hào)整型比較快。因?yàn)閤86構(gòu)架中提供了從有符號(hào)整型轉(zhuǎn)化到浮點(diǎn)型的指令,但沒有提供從無符號(hào)整型轉(zhuǎn)化到浮點(diǎn)的指令。在整數(shù)運(yùn)算中計(jì)算商和余數(shù)時(shí),使用無符號(hào)類型比較快。
3.3 Instruction flow optimization指令流優(yōu)化
第三層優(yōu)化的目標(biāo)是低級(jí)指令流。比較常見的技術(shù)是循環(huán)合并(loop merging),循環(huán)展開(unrolling),軟件流水(software pipelining)。
3.3.1循環(huán)合并
如果兩個(gè)循環(huán)計(jì)數(shù)差不多、循環(huán)執(zhí)行互不相同的操作,可以把它們合并在一起組成一個(gè)循環(huán)。當(dāng)兩個(gè)循環(huán)的負(fù)荷都不滿時(shí),這是非常有用的。
3.3.2循環(huán)展開
循環(huán)展開就是把循環(huán)計(jì)數(shù)小的循環(huán)展開,成為非循環(huán)形式的串行程序,或者把循環(huán)計(jì)數(shù)大的循環(huán)部分展開,減少循環(huán)迭代次數(shù),這樣可以節(jié)省了用于循環(huán)設(shè)置、初始化、增加和校對(duì)循環(huán)計(jì)數(shù)器的時(shí)間。大多數(shù)編譯器可以自動(dòng)完成這項(xiàng)工作,手工編譯會(huì)出現(xiàn)錯(cuò)例如:
for( int i = 0; i < 3; i++ ) array[i] = i;
邏輯上等同于:
array[0] = 0; array[1] = 1, array[2] = 2;
3.3.3軟件流水
軟件流水是用來安排循環(huán)指令,使這個(gè)循環(huán)多次迭代并行執(zhí)行的一種技術(shù)。在嵌套循環(huán)中,編譯器僅對(duì)最里面的循環(huán)執(zhí)行軟件流水,因此對(duì)執(zhí)行周期很少的內(nèi)循環(huán)作循環(huán)展開,外循環(huán)進(jìn)行軟件流水,這樣可以改進(jìn)C代碼并行執(zhí)行的性能。使用軟件流水還應(yīng)當(dāng)注意:盡管軟件流水循環(huán)可以包含內(nèi)聯(lián)函數(shù),但是不能包含函數(shù)調(diào)用;在循環(huán)中不可以有條件終止指令;在循環(huán)體中不可以修改循環(huán)控制變量。
4 總結(jié)語
現(xiàn)代的C和C++編譯器都提供了一定程度上的代碼優(yōu)化。然而,大部分由編譯器執(zhí)行的優(yōu)化僅涉及執(zhí)行速度和代碼大小的一個(gè)平衡。你的程序能夠變得更快或者更小,但是不可能又變快又變小。上面介紹的方法主要是為了提高代碼的效率。但是事實(shí)上,在使用這些技術(shù)提高代碼運(yùn)行速度的同時(shí)會(huì)相應(yīng)的產(chǎn)生一些負(fù)面的影響,比如增加代碼的大小、降低程序可讀性等。不過你可以讓C/C++編譯器來進(jìn)行減少代碼大小的優(yōu)化,而手動(dòng)利用編程來減少代碼的執(zhí)行時(shí)間。在嵌入式程序設(shè)計(jì)中合理地使用這幾種技術(shù)有時(shí)會(huì)達(dá)到很好 的優(yōu)化效果。
參考文獻(xiàn):
[1]王春寧.嵌入式系統(tǒng)編程源代碼解析[M].北京:電子工業(yè)出版社,2002.
[2]王田苗.嵌入式系統(tǒng)設(shè)計(jì)與實(shí)例開發(fā)[M].北京:清華大學(xué)出版社,2002.
[3] Michael Barr.譯者:于志宏 C/C++嵌入式系統(tǒng)編程 [M]. 北京:中國(guó)電力出版社,2001.
[4] Tajana ˇSimuni′c, Luca Benini , Giovanni De Micheli and Mat Hans. Source Code Optimization and Profiling of Energy Consumption in Embedded Systems [J ]. In Proceedings of IEEE International Symposium 誤代碼。
【嵌入式系統(tǒng)編程中的代碼優(yōu)化】相關(guān)文章:
數(shù)控編程M代碼大全09-22
Java用于嵌入式系統(tǒng)的局限03-01
嵌入式系統(tǒng)開發(fā)流程01-29
嵌入式系統(tǒng)基礎(chǔ)知識(shí)10-28
嵌入式系統(tǒng)體系結(jié)構(gòu)12-16
Windows系統(tǒng)中Hosts文件作用11-07