在嵌入式系統(tǒng)中由于資源比較有限,特別是內(nèi)存資源,因此對程序運(yùn)行的性能要求比較高。對執(zhí)行效率高的程序段所占用的空間和運(yùn)行效率進(jìn)行全方位的優(yōu)化,可以對程序運(yùn)行的整體效率將產(chǎn)生可觀的提升。
1、循環(huán)緩沖區(qū)
在一些嵌入式的系統(tǒng)中,常常需要開辟一塊緩沖區(qū)保存數(shù)據(jù)。例如:對于數(shù)據(jù)采集系統(tǒng),需要將一定時間段內(nèi)的數(shù)據(jù)放入一個內(nèi)存區(qū)域中。這個內(nèi)存區(qū)域的放置方法是從低地址開始放置,如果放滿了(到達(dá)了最高的地址),則需要從頭部的低地址開始重新放置。這樣的內(nèi)存結(jié)構(gòu)就組成了一個循環(huán)緩沖區(qū)。
在一般的嵌入式處理器中沒有硬件自動完成循環(huán)放置的功能,通常的做法是在程序的每次循環(huán)中都判斷緩沖區(qū)是否放滿了,顯然這樣的開銷很大。
如果要在程序中執(zhí)行緩沖區(qū)類型的操作,這些操作一般需要占用一塊連續(xù)的內(nèi)存。在棧上分配的內(nèi)存,一般只能在函數(shù)內(nèi)部使用,函數(shù)退出的時候就會被釋放,因此不適合作為緩沖區(qū)使用。而在堆上的內(nèi)存和靜態(tài)內(nèi)存都可以作為緩沖區(qū)內(nèi)存使用。
我們舉例來看下:
#define BUFFERSIZE 256
int x[BUFFERSIZE];
unsigned int k;
unsigned int i;
while(1)
{
k = i & (BUFFERSIZE-1);
x[k] = ImputData();
/*……*/
i++;
}
從程序中可見,數(shù)組x[]是作為程序的緩沖區(qū)使用的,而由于開始并沒有進(jìn)行數(shù)組的初始化,x[]是一個建立在BSS段上的數(shù)組,其大小由BUFFERSIZE確定。
我們看循環(huán)內(nèi)的操作,可以完成自動循環(huán)的過程,這個例程中,當(dāng)i增加到256的時候,k作為數(shù)組下標(biāo),又會返回為0,i本身增加到最大值的時候也會變?yōu)?。
那么大家很容易看出來,由于不需要使用if做判斷,可以節(jié)省幾條程序指令的時間。對于這幾條指令看似節(jié)省的時間不多,但是由于上述語句執(zhí)行的頻率非常高,所以這些時間的節(jié)省占程序總運(yùn)行時間的權(quán)重還是比較大的。尤其對于實(shí)時采樣處理問題,程序必須在指定時間內(nèi)完成一系列的操作。所以對于執(zhí)行效率比較高的指令,哪怕只節(jié)省一條指令,對運(yùn)行效率的提高都是很有意義的。
從以上的例子中可以看出,當(dāng)進(jìn)行程序優(yōu)化的時候,不僅需要考慮程序段運(yùn)行的絕對時間,還應(yīng)該考慮程序段運(yùn)行的頻率。對于運(yùn)行頻率非常高的程序,對其進(jìn)行優(yōu)化會在很大的程度上提高系統(tǒng)的性能。
2、查表法
由于資源有限,程序的運(yùn)行效率在嵌入式系統(tǒng)上比在PC上的程序開發(fā)更為重要。程序的運(yùn)行速度和所占用的存儲器空間這兩個效率問題都是必須考慮的。嵌入式系統(tǒng)程序的運(yùn)行速度與處理器頻率有關(guān)系;而程序所能占用的存儲器空間與ROM或RAM的大小有關(guān)系。
在當(dāng)前的嵌入式系統(tǒng)中,程序的運(yùn)行速度比程序所占用的存儲器空間顯得更重要,一是存儲器方便擴(kuò)展,二是存儲器的容量是比較容易控制,程序運(yùn)行占用的處理器時間比較難控制。
在設(shè)計(jì)過程中,程序的容量和速度在很多時候是有些矛盾的,在程序中犧牲一定的存儲容量換取程序的運(yùn)行速度,這對于嵌入式系統(tǒng)來說是有一定好處的。典型的例子就是查表法。
例如:在一個4位的二進(jìn)制數(shù)中,確定有幾位為1,也就是要統(tǒng)計(jì)0x0~0xf中的任何一個數(shù),中間有幾個1。
典型的思路就是使用循環(huán)的方法讓程序在這個4位的數(shù)中依次查找各個位是否為1,最后累加得出1的數(shù)目。那么在實(shí)現(xiàn)這個簡單的功能的過程中,需要進(jìn)行4次循環(huán)、4次判斷,這是有一定開銷的,占用了不少處理器的時間。從程序需要實(shí)現(xiàn)的功能考慮,輸入是一個4位的數(shù),范圍是0x0~0xf,輸出數(shù)的范圍是0~4,這實(shí)際上是完成了一種映射功能,可以換成第二種查表法的思路,就是構(gòu)造一個16個元素的數(shù)組,可以通過數(shù)組得到結(jié)果。實(shí)際上數(shù)組的下標(biāo)就是輸入的數(shù)值,而數(shù)組的元素就是輸出的數(shù)值。
那么很容易看出來,這種做法的優(yōu)點(diǎn)是每個數(shù)值的獲取非常快,代價則是增加了一個有16個元素的數(shù)組。數(shù)組是預(yù)先固化好的常量,而不是程序動態(tài)生成的,這種利用靜態(tài)空間換取程序執(zhí)行時間的方式轉(zhuǎn)換后的程序執(zhí)行效率非常高。如果把它應(yīng)用在使用頻率很高的程序中,就可以節(jié)省很多的系統(tǒng)開銷。
同樣,大家可以考慮一下如果是查找8位數(shù)中的1的個數(shù)怎么做?16位呢?如果變通。
3、針對循環(huán)執(zhí)行效率的優(yōu)化
循環(huán)是C語言程序中的常用語法功能,由于循環(huán)執(zhí)行的次數(shù)較多,占程序執(zhí)行時間的權(quán)重大,所以對循環(huán)的優(yōu)化是提高程序效率的關(guān)鍵點(diǎn)。
例如,
void change_list_value()
{
int i,count;
POSITION pos;
CPtrList* plist;
plist = get_start(pos);
for(i = 0; i < get_count(); i++) ? ? count = get_count(); ? ? ?
{ for(i = 0; i < count ; i++)
plist = get_next(pos); {}
set_val (plist);
}
return 0;
}
上面這個循環(huán)代碼左邊是原始寫法,右邊是改進(jìn)的。可以發(fā)現(xiàn)循環(huán)中執(zhí)行的函數(shù)減少了,原來的get_count()函數(shù)從原來的內(nèi)部轉(zhuǎn)移到了循環(huán)外部,也就是說這個循環(huán)函數(shù)改進(jìn)后只執(zhí)行一次,如果這個鏈表中的元素有幾千個至幾萬個,那么第一段代碼比第二段代碼多執(zhí)行了幾千條幾萬條的語句,這樣會導(dǎo)致時間上巨大的開銷。
總結(jié):在循環(huán)系統(tǒng)中,針對于循環(huán)條件,應(yīng)該盡可能地使用臨時變量來替代函數(shù)調(diào)用,這樣可以在循環(huán)次數(shù)較多的情況下,減少大量不必要的函數(shù)調(diào)用。
你有沒有更好的優(yōu)化技巧也分享出
責(zé)任編輯:haq
-
嵌入式
+關(guān)注
關(guān)注
5086文章
19143瀏覽量
306045 -
程序
+關(guān)注
關(guān)注
117文章
3791瀏覽量
81153
原文標(biāo)題:程序的優(yōu)化技巧
文章出處:【微信號:CanaanTech,微信公眾號:嘉楠科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論