




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、DSP程序優(yōu)化方法(1)1、選擇合適的算法和數(shù)據(jù)結(jié)構(gòu)選擇一種合適的數(shù)據(jù)結(jié)構(gòu)很重要,如果在一堆隨機存放的數(shù)中使用了大量的插入和刪除 指令,那使用鏈表要快得多。數(shù)組與指針語句具有十分密切的關(guān)系,一般來說,指針比較靈 活簡潔,而數(shù)組則比較直觀,容易理解。對于大部分的編譯器,使用指針比使用數(shù)組生成的 代碼更短,執(zhí)行效率更高。在許多種情況下,可以用指針運算代替數(shù)組索引,這樣做常常能產(chǎn)生又快又短的代碼。 與數(shù)組索引相比,指針一般能使代碼速度更快,占用空間更少。使用多維數(shù)組時差異更明顯。 下面的代碼作用是相同的,但是效率不一樣。數(shù)組索引指針運算For(;)p=arrayA=arrayt+;for(;)a=*
2、(p+);0000000000 0 0 0 0 0指針方法的優(yōu)點是,array的地址每次裝入地址p后,在每次循環(huán)中只需對p增量操作。 在數(shù)組索引方法中,每次循環(huán)中都必須根據(jù)t值求數(shù)組下標的復雜運算。2、使用盡量小的數(shù)據(jù)類型能夠使用字符型(char)定義的變量,就不要使用整型(int)變量來定義;能夠使用整 型變量定義的變量就不要用長整型(long int),能不使用浮點型(float)變量就不要使用浮 點型變量。當然,在定義變量后不要超過變量的作用范圍,如果超過變量的范圍賦值,C編 譯器并不報錯,但程序運行結(jié)果卻錯了,而且這樣的錯誤很難發(fā)現(xiàn)。在ICCAVR中,可以在 Options中設(shè)定使用p
3、rintf參數(shù),盡量 使用基本型參數(shù) (%c、d、x、X、u和%s格式說明符),少用長整型參數(shù)(%ld、%lu、%lx 和%lX格式說明符),至于浮點型的參數(shù)(f)則盡量不要使用,其它C編譯器也一樣。 在其它條件不變的情況下,使用%f參數(shù),會使生成的代碼的數(shù)量增加很多,執(zhí)行速度降 低。3、減少運算的強度、查表(游戲程序員必修課)一個聰明的游戲大蝦,基本上不會在自己的主循環(huán)里搞什么運算工作,絕對是先計算好了, 再到循環(huán)里查表??聪旅娴睦樱号f代碼:long factorial(int i)if (i = 0)return 1;elsereturn i * factorial(i - 1);新代碼
4、:static long factorial_table=1 , 1 , 2 , 6 , 24 , 120 , 720/* etc */ ;long factorial(int i)return factorial_table;如果表很大,不好寫,就寫一個init函數(shù),在循環(huán)外臨時生成表格。、求余運算a=a%8;可以改為:a=a&7;說明:位操作只需一個指令周期即可完成,而大部分的C編譯器的“ % ”運算均是調(diào)用 子程序來完成,代碼長、執(zhí)行速度慢。通常,只要求是求2n方的余數(shù),均可使用位操作 的方法來代替。、平方運算a=pow(a, 2.0);可以改為:a=a*a;說明:在有內(nèi)置硬件乘法器的單
5、片機中(如51系列),乘法運算比求平方運算快得多, 因為浮點數(shù)的求平方是通過調(diào)用子程序來實現(xiàn)的,在自帶硬件乘法器的AVR單片機中,如 ATMega163中,乘法運算只需2個時鐘周期就可以完成。既使是在沒有內(nèi)置硬件乘法器的 AVR單片機中,乘法運算的子程序比平方運算的子程序代碼短,執(zhí)行速度快。如果是求3次方,如:a=pow(a, 3 。 0);更改為:a=a*a*a ;則效率的改善更明顯。(4)、用移位實現(xiàn)乘除法運算a=a*4;b=b/4;可以改為:a=a2;通常如果需要乘以或除以2n,都可以用移位的方法代替。在ICCAVR中,如果乘以2n, 都可以生成左移的代碼,而乘以其它的整數(shù)或除以任何數(shù),
6、均調(diào)用乘除法子程序。用移位的 方法得到代碼比調(diào)用乘除法子程序生成的代碼效率高。實際上,只要是乘以或除以一個整數(shù), 均可以用移位的方法得到結(jié)果,如:a=a*9可以改為:a=(a3)+a采用運算量更小的表達式替換原來的表達式,下面是一個經(jīng)典例子:舊代碼:x = w % 8;y = pow(x , 2.0);z = y * 33;for (i = 0;i MAX;i+)h = 14 * i;printf(%d” , h);新代碼:x = w & 7;/*位操作比求余運算快*/y = x * x;/*乘法比平方運算快*/z = (y 5) + y; /*位移乘法比乘法快*/for (i = h = 0
7、; i 0)while (*q (*r = a / *q)*q = (*q + *r) 1 ;*r = a - *q * *q ;推薦的代碼:/假設(shè)q != rvoid isqrt(unsigned long a , unsigned long* q, unsigned long* r)unsigned long qq,rr ;qq = a ;if (a 0)while (qq (rr = a / qq)qq = (qq + rr) 1 ;rr = a - qq * qq ;*q = qq ;*r = rr ;DSP程序優(yōu)化方法(2)5、循環(huán)優(yōu)化、充分分解小的循環(huán)要充分利用CPU的指令緩存,就
8、要充分分解小的循環(huán)。特別是當循環(huán)體本身很小的 時候,分解循環(huán)可以提高性能。注意:很多編譯器并不能自動分解循環(huán)。不好的代碼:/ 3D轉(zhuǎn)化:把矢量V和4x4矩陣M相乘for (i = 0 ; i 4 ; i +)r = 0 ;for (j = 0 ; j 4 ; j +)推薦的代碼:r0 = M00*V0 + M10*V1 + M20*V2 + M30*V3;r1 = M01*V0 + M11*V1 + M21*V2 + M31*V3;r2 = M02*V0 + M12*V1 + M22*V2 + M32*V3;r3 = M03*V0 + M13*V1 + M23*V2 + M33*v3;、提取公
9、共部分對于一些不需要循環(huán)變量參加運算的任務(wù)可以把它們放到循環(huán)外面,這里的任務(wù)包括表達 式、函數(shù)的調(diào)用、指針運算、數(shù)組訪問等,應(yīng)該將沒有必要執(zhí)行多次的操作全部集合在一起, 放到一個init的初始化程序中進行。、延時函數(shù)通常使用的延時函數(shù)均采用自加的形式:void delay (void)unsigned int i;for (i=0;i1000;i+);將其改為自減延時函數(shù):void delay (void)unsigned int i;兩個函數(shù)的延時效果相似,但幾乎所有的C編譯對后一種函數(shù)生成的代碼均比前一種代碼 少13個字節(jié),因為幾乎所有的MCU均有為0轉(zhuǎn)移的指令,采用后一種方式能夠生 成這
10、類指令。在使用while循環(huán)時也一樣,使用自減指令控制循環(huán)會比使用自加指令控制 循環(huán)生成的代碼更少13個字母。但是在循環(huán)中有通過循環(huán)變量“ i ”讀寫數(shù)組的指令時, 使用預減循環(huán)有可能使數(shù)組超界,要引起注意。(4)、while循環(huán)和 dowhile循環(huán)用while循環(huán)時有以下兩種循環(huán)形式:unsigned int i;i=0;while (i1000)i+;/用戶程序或.:unsigned int i;i=1000;doi-;/ 用戶程序在這兩種循環(huán)中,使用do while循環(huán)編譯后生成的代碼的長度短于while循環(huán)。(6)、循環(huán)展開這是經(jīng)典的速度優(yōu)化,但許多編譯程序(如gcc -funrol
11、l-loops)能自動完成這個事,所以現(xiàn) 在你自己來優(yōu)化這個顯得效果不明顯。舊代碼:for (i = 0; i 100; i+)do_stuff(i);新代碼:for (i = 0; i 10;)do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;do_stuff(i); i+;可以看出,新代碼里比較指令由100次降低為10次,循環(huán)時間節(jié)約了 90%。不過注 意
12、:對于中間變量或結(jié)果被更改的循環(huán),編譯程序往往拒絕展開,(怕?lián)熑螁h),這時 候就需要你自己來做展開工作了。還有一點請注意,在有內(nèi)部指令cache的CPU上(如MMX芯片),因為循環(huán)展開的 代碼很大,往往cache溢出,這時展開的代碼會頻繁地在CPU的cache和內(nèi)存之間調(diào)來 調(diào)去,又因為cache速度很高,所以此時循環(huán)展開反而會變慢。還有就是循環(huán)展開會影響 矢量運算優(yōu)化。(6)、循環(huán)嵌套把相關(guān)循環(huán)放到一個循環(huán)里,也會加快速度。舊代碼:for (i = 0; i MAX; i+)/* initialize 2d array to 0s */for (j = 0; j MAX; j+)aj =
13、0.0;for (i = 0; i MAX; i+)/* put 1s along the diagonal */a = 1.0;新代碼 :for (i = 0; i MAX; i+)/* initialize 2d array to 0s */for (j = 0; j MAX; j+)aj = 0.0;a = 1.0;/* put 1s along the diagonal */(7)、Switch語句中根據(jù)發(fā)生頻率來進行case排序Switch可能轉(zhuǎn)化成多種不同算法的代碼。其中最常見的是 跳轉(zhuǎn)表和比較鏈/樹。當 switch用比較鏈的方式轉(zhuǎn)化時,編譯器會產(chǎn)生if-else-if的嵌套代碼
14、,并按照順序進行比較, 匹配時就跳轉(zhuǎn)到滿足條件的語句執(zhí)行。所以可以對case的值依照發(fā)生的可能性進行排序, 把最有可能的放在第一位,這樣可以提高性能。此外,在case中推薦使用小的連續(xù)的整數(shù), 因為在這種情況下,所有的編譯器都可以把switch轉(zhuǎn)化成跳轉(zhuǎn)表。不好的代碼:int days_in_month, short_months, normal_months, long_months ;0 0 0 0 0 0switch (days_in_month)case 28:case 29:short_months + ;break ;case 30:normal_months + ;break ;
15、case 31:long_months +;break ;default:cout month has fewer than 28 or more than 31 days endl ;break ;推薦的代碼:int days_in_month , short_months , normal_months , long_months ;0 0 0 0 0 0switch (days_in_month)case 31:long_months + ;break ;case 30:normal_months + ;break ;case 28:case 29:short_months + ;bre
16、ak ;default:cout month has fewer than 28 or more than 31 days type)case FREQUENT_MSG1:handleFrequentMsg();break;case FREQUENT_MSG2:handleFrequentMsg2();break;。case FREQUENT_MSGn:handleFrequentMsgn();break;default:/嵌套部分用來處理不經(jīng)常發(fā)生的消息switch (pMsg-type)case INFREQUENT_MSG1:handleInfrequentMsg1();break;ca
17、se INFREQUENT_MSG2:handleInfrequentMsg2();break;case INFREQUENT_MSGm:handleInfrequentMsgm();break;如果switch中每一種情況下都有很多的工作要做,那么把整個switch語句用一個指向函 數(shù)指針的表來替換會更加有效,比如下面的switch語句,有三種情況:enum MsgTypeMsg1, Msg2, Msg3switch (ReceiveMessage()case Msg1;0 0 0 0 0 0case Msg2;00000case Msg3;00000為了提高執(zhí)行速度,用下面這段代碼來替換這
18、個上面的switch語句。/*準備工作*/int handleMsgl(void);int handleMsg2(void);int handleMsg3(void);/*創(chuàng)建一個函數(shù)指針數(shù)組*/int (*MsgFunction )()=handleMsg1 , handleMsg2 , handleMsg3;/*用下面這行更有效的代碼來替換switch語句*/ status=MsgFunctionReceiveMessage()();、循環(huán)轉(zhuǎn)置有些機器對JNZ(為0轉(zhuǎn)移)有特別的指令處理,速度非常快,如果你的循環(huán)對方向不敏 感,可以由大向小循環(huán)。舊代碼:for (i = 1; i = MA
19、X; i+) 0 0 0 新代碼:i = MAX+1;while (-i)000不過千萬注意,如果指針操作使用了 i值,這種方法可能引起指針越界的嚴重錯誤(i =MAX+1;)。當然你可以通過對i做加減運算來糾正,但是這樣就起不到加速的作用,除非類似于以下情況: 舊代碼:char aMAX+5;for (i = 1; i = MAX; i+)*(a+i+4)=0;新代碼:i = MAX+1;while (-i)*(a+i+4)=0;、公用代碼塊一些公用處理模塊,為了滿足各種不同的調(diào)用需要,往往在內(nèi)部采用了大量的if-then-else 結(jié)構(gòu),這樣很不好,判斷語句如果太復雜,會消耗大量的時間的,
20、應(yīng)該盡量減少公用代碼塊 的使用。(任何情況下,空間優(yōu)化和時間優(yōu)化都是對立的-東樓)。當然,如果僅僅是 一個(3=x)之類的簡單判斷,適當使用一下,也還是允許的。記住,優(yōu)化永遠是追求一種 平衡,而不是走極端。提升循環(huán)的性能要提升循環(huán)的性能,減少多余的常量計算非常有用(比如,不隨循環(huán)變化的計算)。不好的代碼(在for()中包含不變的if():for(i。)if( CONSTANT0 )DoWork0( i ) ; /假設(shè)這里不改變CONSTANT。的值elseDoWork1( i ) ; /假設(shè)這里不改變CONSTANT。的值推薦的代碼:if( CONSTANT0 )for( i。)DoWork0
21、( i );elsefor( i。 )DoWork1( i ); 如果已經(jīng)知道if()的值,這樣可以避免重復計算。雖然不好的代碼中的分支可以簡單地預 測,但是由于推薦的代碼在進入循環(huán)前分支已經(jīng)確定,就可以減少對分支預測的依賴。、選擇好的無限循環(huán)在編程中,我們常常需要用到無限循環(huán),常用的兩種方法是while (1)和for (;)。這 兩種方法效果完全一樣,但那一種更好呢?然我們看看它們編譯后的代碼:編譯前:while (1);編譯后:mov eax,1test eax, eaxje foo+23hjmp foo+18h編譯前:for (;);編譯后:jmp foo+23h顯然,for (;)指
22、令少,不占用寄存器,而且沒有判斷、跳轉(zhuǎn),比while (1)好。DSP程序優(yōu)化方法(3)6、提高CPU的并行性使用并行代碼盡可能把長的有依賴的代碼鏈分解成幾個可以在流水線執(zhí)行單元中并行執(zhí)行的沒有依賴的 代碼鏈。很多高級語言,包括C+,并不對產(chǎn)生的浮點表達式重新排序,因為那是一個相 當復雜的過程。需要注意的是,重排序的代碼和原來的代碼在代碼上一致并不等價于計算結(jié) 果一致,因為浮點操作缺乏精確度。在一些情況下,這些優(yōu)化可能導致意料之外的結(jié)果。幸 運的是,在大部分情況下,最后結(jié)果可能只有最不重要的位(即最低位)是錯誤的。不好的代碼:double a100, sum ;int i ;sum = 0.0
23、f ;for (i=0 ; i100 ; i+)sum += a ;推薦的代碼:double a100, sum1, sum2, sum3, sum4, sum ;int i;sum1 = sum2 = sum3 = sum4 = 0.0 ;for (i = 0 ; i 100 ; i += 4)sum1 += a ;sum2 += ai+1;sum3 += ai+2;sum4 += ai+3;sum = (sum4+sum3)+(sum1+sum2);要注意的是:使用4路分解是因為這樣使用了 4段流水線浮點加法,浮點加法的每 一個段占用一個時鐘周期,保證了最大的資源利用率。避免沒有必要的讀寫
24、依賴 當數(shù)據(jù)保存到內(nèi)存時存在讀寫依賴,即數(shù)據(jù)必須在正確寫入后才能再次讀取。雖然 AMD Athlon等CPU有加速讀寫依賴延遲的硬件,允許在要保存的數(shù)據(jù)被寫入內(nèi)存前讀取出來, 但是,如果避免了讀寫依賴并把數(shù)據(jù)保存在內(nèi)部寄存器中,速度會更快。在一段很長的又互 相依賴的代碼鏈中,避免讀寫依賴顯得尤其重要。如果讀寫依賴發(fā)生在操作數(shù)組時,許多編 譯器不能自動優(yōu)化代碼以避免讀寫依賴。所以推薦程序員手動去消除讀寫依賴,舉例來說, 引進一個可以保存在寄存器中的臨時變量。這樣可以有很大的性能提升。下面一段代碼是一 個例子:不好的代碼:float xVECLEN, yVECLEN, zVECLEN;for (
25、unsigned int k = 1 ; k VECLEN ; k +)xk = xk-1 + yk;for (k = 1 ; k VECLEN ; k+)xk = zk * (yk - xk-1);推薦的代碼:float xVECLEN, yVECLEN,zVECLEN;0 0 0 0 0 0float t(x0);for ( unsigned int k = 1 ; k VECLEN ; k +)t = t + yk;xk = t ;t = x0;for (k = 1 ; k b-c4-aardvark +a-b-c4-baboon +a-b-c4-cheetah +a-b-c4-dog;
26、新代碼:struct animals * temp = a-b-c4;total =temp-aardvark +temp-baboon +temp-cheetah +temp-dog;一些老的C語言編譯器不做聚合優(yōu)化,而符合ANSI規(guī)范的新的編譯器可以自動完成這 個優(yōu)化,看例子:float a, b, c, d, f, g;0 0 0a = b / c * d;f = b * g / c;這種寫法當然要得,但是沒有優(yōu)化float a, b , c , d ,f , g;000a = b / c * d;f = b / c * g;如果這么寫的話,一個符合ANSI規(guī)范的新的編譯器可以只計算b/
27、c 一次,然后將結(jié)果代 入第二個式子,節(jié)約了一次除法運算。8、函數(shù)優(yōu)化(1) Inline 函數(shù)在C+中,關(guān)鍵字Inline可以被加入到任何函數(shù)的聲明中。這個關(guān)鍵字請求編譯器用函 數(shù)內(nèi)部的代碼替換所有對于指出的函數(shù)的調(diào)用。這樣做在兩個方面快于函數(shù)調(diào)用:第一, 省去了調(diào)用指令需要的執(zhí)行時間;第二,省去了傳遞變元和傳遞過程需要的時間。但是使用 這種方法在優(yōu)化程序速度的同時,程序長度變大了,因此需要更多的ROM o使用這種優(yōu)化在Inline函數(shù)頻繁調(diào)用并且只包含幾行代碼的時候是最有效的。(2)不定義不使用的返回值函數(shù)定義并不知道函數(shù)返回值是否被使用,假如返回值從來不會被用到,應(yīng)該使用void來 明確聲明函數(shù)不返回任何值。(3)減少函數(shù)調(diào)用參數(shù)使用全局變量比函數(shù)傳遞參數(shù)更加有效率。這樣做去除了函數(shù)調(diào)用參數(shù)入棧和函數(shù)完 成后參數(shù)出棧所需要的時間。然而決定使用全局變量會影響程序的模塊化和重入,故要慎重 使用。(4)所有函數(shù)都應(yīng)該有原型定義一般來說,所有函數(shù)都應(yīng)該有原型定義。原型定義可以傳達給編譯器更多的可能用于優(yōu)化的 信息。(5)盡可能使用常量(const)盡可能使用常量(const)。C+標準規(guī)定,如果一個const聲明的對象的地址不被獲取, 允許編譯器不對它分配儲存空間。這樣可以使代碼更有效率,而且可以生成更好的代碼。(6)把本地函數(shù)聲明為靜態(tài)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024廣西交投科技有限公司招聘18人筆試參考題庫附帶答案詳解
- 2024廣東湛江環(huán)北部灣水資源管理有限公司招聘4人筆試參考題庫附帶答案詳解
- 2024年泉州升華實業(yè)有限公司招聘3人筆試參考題庫附帶答案詳解
- 第10課《阿長與山海經(jīng)》教學設(shè)計 2024-2025學年統(tǒng)編版語文七年級下冊標簽標題
- 2025年智能投顧項目建議書
- 國家開放大學漢語言本科《古代漢語專題》期末紙質(zhì)考試第二大題多項選擇題庫2025春期考試版
- 《復活(節(jié)選)》教學設(shè)計 2024-2025學年統(tǒng)編版高中語文選擇性必修上冊
- 第一章第二節(jié)人口教學設(shè)計2023-2024學年人教版地理八年級上冊
- 第二單元第五課《計算機的資源管理》教學設(shè)計-2023-2024學年粵教版(2019)初中信息技術(shù)七年級上冊
- 2024年12月浙江舟山市檔案館編外人員公開招聘1人筆試歷年典型考題(歷年真題考點)解題思路附帶答案詳解
- 醫(yī)院智能化系統(tǒng)內(nèi)網(wǎng)、外網(wǎng)及設(shè)備網(wǎng)系統(tǒng)拓撲圖-可編輯課件
- 安徽省2024年中考語文真題試卷【附答案】
- 2024年南京科技職業(yè)學院單招職業(yè)適應(yīng)性測試題庫帶答案
- DB52-T 1780-2024 醬香型白酒安全生產(chǎn)規(guī)范
- 2024年皖西衛(wèi)生職業(yè)學院單招職業(yè)適應(yīng)性測試題庫及參考答案
- 【信息技術(shù)】信息技術(shù)及其應(yīng)用教學課件 2023-2024學年人教-中圖版(2019)高中信息技術(shù)必修二
- (正式版)JTT 1502-2024 直升機救生員搜救作業(yè)手勢信號要求
- 2024年社區(qū)工作者考試必背1000題題庫附答案(滿分必刷)
- 線蟲病疫木及異??菟浪蓸涮幹猛稑朔桨福夹g(shù)方案技術(shù)標)
- 2024年鞍山職業(yè)技術(shù)學院單招職業(yè)傾向性測試題庫(500題)含答案解析
- 2024年湖北省宏泰國有資本投資運營集團有限公司招聘筆試參考題庫含答案解析
評論
0/150
提交評論