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