DSP編程技巧之29---答疑解惑哪家強(qiáng)之(4)
答疑解惑哪家強(qiáng)?當(dāng)屬我們EEPW最強(qiáng)。。。接下來(lái)繼續(xù)我們的答疑解惑。
本文引用地址:http://2s4d.com/article/266495.htm22. 除了使用編譯器的優(yōu)化選項(xiàng)之外,還可以使用什么方法提高程序的性能?
編譯器的優(yōu)化選項(xiàng),只能在代碼滿足眾多選項(xiàng)的要求時(shí),才能得到較好的優(yōu)化效果。在我們編程的時(shí)候,首先要做到心里有數(shù),盡可能使用一些高效的編程方式,例如使用右移操作代替除以2的倍數(shù)的操作,可以大幅度地減少代碼運(yùn)行時(shí)間等。這些技巧很多是與C/C++的熟練使用所相關(guān)的。此外,根據(jù)器件的特點(diǎn),例如是否包含F(xiàn)PU、CLA等,把特定的代碼放在不同的區(qū)域執(zhí)行,也能起到提高程序性能的效果;根據(jù)代碼對(duì)性能的要求,把它們運(yùn)行在不同的位置,例如RAM快于Flash,Flash又快于XINTF等;在器件包含數(shù)學(xué)表的情況下,使用內(nèi)建的數(shù)序函數(shù)庫(kù),而不是標(biāo)準(zhǔn)的C數(shù)學(xué)庫(kù)等。在此我們可以給出一些提示:
1) 代碼運(yùn)行在Flash中
一定要使能預(yù)讀緩沖區(qū),并配置適當(dāng)?shù)牡却隣顟B(tài)。一般在各個(gè)器件的頭文件與外設(shè)示例包里都有對(duì)應(yīng)的例子。
2) 把時(shí)間關(guān)鍵的代碼和/常數(shù)數(shù)組等從Flash復(fù)制到RAM中運(yùn)行
在RAM中運(yùn)行時(shí),最大的指令周期比Flash中運(yùn)行時(shí)要高,其執(zhí)行速度也要快出不少,所以可以根據(jù)需要把實(shí)時(shí)性能要求較高的程序復(fù)制到RAM中運(yùn)行,具體的方法和實(shí)例可以參考http://www.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=spra958l下面的《Running an Application from Internal Flash Memory on the TMS320F28xxx DSP》。
3) 評(píng)估代碼和數(shù)據(jù)的存儲(chǔ)地址的劃分,并根據(jù)需要修改鏈接文件
i. 如果某段代碼和它所讀取的數(shù)據(jù)位于同一個(gè)物理內(nèi)存區(qū)間中,則因?yàn)樗鼈兪褂孟嗤牡刂房偩€等資源,無(wú)法同時(shí)訪問(wèn),造成了資源的沖突,這會(huì)降低程序的性能,所以最好把代碼和數(shù)據(jù)保存在不同的內(nèi)存區(qū)間中。
ii. 等待狀態(tài)(wait)會(huì)降低系統(tǒng)性能,因?yàn)镃PU會(huì)執(zhí)行過(guò)多的無(wú)用狀態(tài)且在此期間無(wú)法處理別的任務(wù):當(dāng)CPU讀取或者訪問(wèn)存儲(chǔ)單元或者外設(shè)的時(shí)候,該存儲(chǔ)器或者外設(shè)有可能在CPU默認(rèn)分配的時(shí)間內(nèi)無(wú)法完成數(shù)據(jù)的傳輸,此時(shí)就需要在CPU的ready信號(hào)中插入等待狀態(tài),直到數(shù)據(jù)傳輸完成才能讓CPU繼續(xù)執(zhí)行別的任務(wù)。C28x器件上,大部分的SARAM都是零等待的,但是在C2833x器件中,有一些模塊卻不是,例如某些Flash/OTP的訪問(wèn)等。
iii. 如果在代碼中大量使用兩個(gè)數(shù)據(jù)緩沖區(qū),則把兩個(gè)數(shù)據(jù)緩沖區(qū)存放在不同的RAM模塊中有可能會(huì)提高代碼的性能,因?yàn)榇罅孔x寫(xiě)同一塊RAM區(qū)間會(huì)產(chǎn)生更多的流水線停滯,造成性能的降低。
4) 使用編譯器中的統(tǒng)一內(nèi)存模式--unified_memory
此模式把所有的存儲(chǔ)空間定義為一個(gè)整體,這樣編譯器在編譯時(shí)就可以使用RPT與PREAD指令來(lái)處理大部分的內(nèi)存復(fù)制調(diào)用和結(jié)構(gòu)體的分配。
5) 使用Flash和外部存儲(chǔ)器
如果代碼需要在Flash或外部存儲(chǔ)器中運(yùn)行,則在編譯時(shí)開(kāi)啟-me選項(xiàng)。它將禁止編譯器使用快速分支指令(SBF/BF),轉(zhuǎn)而使用普通的跳轉(zhuǎn)指令(SB/B)。BF指令在默認(rèn)情況下是被啟用的,它能夠?qū)⑻D(zhuǎn)分支使用的指令周期從7個(gè)降低到4個(gè),在零等待狀態(tài)的SAM中執(zhí)行時(shí),快速分支指令的預(yù)讀特性使得它較為高效,但是在非零等待的存儲(chǔ)器中執(zhí)行時(shí),SBF/BF的預(yù)讀反而造成了性能的下降,此時(shí)需要人為地對(duì)預(yù)讀和等待進(jìn)行規(guī)劃。
6) 使用內(nèi)聯(lián)函數(shù)
在編譯時(shí)開(kāi)啟內(nèi)聯(lián)函數(shù)功能,則編譯器會(huì)自動(dòng)把多次調(diào)用的函數(shù)進(jìn)行內(nèi)聯(lián),大大減少函數(shù)調(diào)用和返回操作所帶來(lái)的開(kāi)銷。當(dāng)然,根據(jù)“空間換時(shí)間”的原則,開(kāi)啟內(nèi)聯(lián)會(huì)增加一定的代碼尺寸。
23. 為什么一個(gè)char類型的數(shù)組中,每個(gè)元素都占用了16bit的地址?
這是因?yàn)樵贑28x上,字節(jié)(byte)和字(word)是等價(jià)的:也就是說(shuō)它們都是16位或者說(shuō)16比特(bit)寬的,即sizeof(int) == sizeof(char) == 1。
24. sizeof(int) == sizeof(char) == 1貌似與ANSI標(biāo)準(zhǔn)是相違背的?
在ANSI/ISO的C定義中,sizeof操作符以字節(jié)形式給出了其操作數(shù)的存儲(chǔ)大小。ANSI/ISO還規(guī)定,sizeof操作符取char的值時(shí),返回值為1。因?yàn)門(mén)MS320C28x中的字節(jié)是16位的,char也是16位的,所以sizeof的結(jié)果符合ANSI標(biāo)準(zhǔn)的。
作為補(bǔ)充,選16位,而不是8位或者別的什么位數(shù)作為char的寬度,主要是為了統(tǒng)一尋址的便利,雖然在某種程度上說(shuō)這增加了一定的存儲(chǔ)器空間占用,或者說(shuō)浪費(fèi)了一些空間,因?yàn)樗鼈冊(cè)诖鎯?chǔ)空間中制造了一些空洞。
25. 如果char是16位的,那么如何高效地訪問(wèn)8位的值?
可以使用__byte()和__mov_byte()這樣的編譯器內(nèi)聯(lián)函數(shù)。請(qǐng)參考http://2s4d.com/article/265102.htm。
26. 編譯結(jié)果提示undefined symbols,名字中包含$符號(hào),怎么破?
名字中帶美元符號(hào)的函數(shù),例如FS$$MPY, FS$$TOL等,都是RTS庫(kù)里的內(nèi)置函數(shù),編譯器提示我們這些函數(shù)未定義,表明我們沒(méi)有把對(duì)應(yīng)的RTS庫(kù)給加入到工程中,例如MPY是數(shù)學(xué)函數(shù),需要添加相關(guān)的數(shù)學(xué)庫(kù),例如FPU數(shù)學(xué)庫(kù)等。
27. 鏈接器提示“_c_int00 is not defined”,怎么破?
在http://2s4d.com/article/262926.htm這篇文章中,已經(jīng)分析了_c_int00的含義。找不到_c_int00的話,說(shuō)明我們遺漏了包含它的RTS庫(kù),例如 rts2800_ml.lib、rts2800_fpu32.lib等待,這些RTS庫(kù)的具體區(qū)別在答疑解惑的第15條中已經(jīng)有對(duì)比了(http://2s4d.com/article/265108.htm)。
28. 新版本的編譯器中,printf()/sprintf()函數(shù)貌似要使用更多的棧?
這是因?yàn)閜rintf()函數(shù)被重新修改了,以支持多個(gè)級(jí)別的printf格式說(shuō)明符支持和修正,以減少代碼大小和總內(nèi)存大小(包括bss)。printf由sprintf()間接調(diào)用,它使用一個(gè)400個(gè)元素的大小的局部數(shù)組。為了保存一致性,printf()一直都在使用這么大的內(nèi)存空間,而編譯器也在盡量避免使用malloc()進(jìn)行內(nèi)存分配。與老版本所不同的的是,此數(shù)組以前是靜態(tài)的,而現(xiàn)在它被保存在.bss,而不是棧中;這樣做的目的是,如果用戶使用C I/O,則他們往往會(huì)在使用合適尺寸的棧的同時(shí)盡量減小.bss的使用。
c++相關(guān)文章:c++教程
評(píng)論