在前文《如何為嵌入式軟件開發選擇編譯器》中講到編譯器對于嵌入式軟件開發的重要性,以及如何選擇一款優秀的編譯器。 文中也比較了現有主流編譯器的編譯優化性能,IAR Embedded Workbench編譯器不論在輸出代碼體積還是性能均處于業界領先地位。
本文中,我們將以IAR Embedded Workbench編譯器為例,闡述如何配置編譯優化選項,以達到嵌入式軟件代碼性能和體積的最佳平衡。由于篇幅關系,本主題將會分成上、下兩篇。
編譯器代碼構建過程
在介紹如何配置編譯器優化選項之前,讓我們先來了解下編譯器構建的過程。 以IAR Embedded Workbench編譯器為例,其代碼構建過程如下圖。
構建過程分為兩部分:前端和后端。
前端主要將C代碼通過解析器(Parser)生產中間代碼(Intermediate Code),在這個過程中會介入優化器(High-Level Optimizer),其優化策略包括函數內聯(Function in lining), 冗余代碼消除(Dead code elimination), 循環展開(Loop unrolling)等。
后端則將中間代碼通過目標代碼生成器(Code Generator)生成目標匯編代碼(Target Code),在這個過程中也會介入優化器(Low-Level Optimizer),其優化策略包括調度(Scheduling), 窺視孔(Peephole), 函數調用優化(Cross call)等。 然后由匯編器(Assembler)將匯編代碼轉換成目標機器碼(Object Code)。 最后,通過鏈接器(Linker),將所有的目標機器碼鏈接成elf格式的可執行二進制代碼文件。 在鏈接階段也有相應的優化器(Linker time optimization)進行優化。
IAR Embedded Workbench
編譯優化選項介紹
在IAR Embedded Workbench(基于EWARM v9.32.2)中通過菜單欄(Project -> Options)打開項目選項界面,選中“C/C++ Compiler”欄目,并且在右邊選項卡選中“Optimizations”,即可進行編譯優化選項配置,如下圖所示。
1. 編譯優化等級配置
如下圖所示,IAR Embedded Workbench共分為4個優化等級(None, Low, Medium, High),其中等級“High”又分為3個子優化等級(Balanced, Size, Speed)。 下表是各個優化等級對應的優化策略總覽。
? 選擇“None”,編譯器只會進行無用代碼消除等基本優化,但編譯速度快,并且最適合C/C++源代碼調試。
? 最高優化等級除了High(Balanced)之外,也可以選擇High(Size)對于代碼體積進行極致優化; 或者選擇High(Speed) ,并且勾選 No size constraints,則對于代碼性能進行極致優化。
關于編譯優化微調項(Enabled transformations)配置方法,我們將在《深入淺出編譯優化選項(下)》詳細介紹,敬請關注。
2. 多文件編譯(Multi-file Compilation)
通常情況下,編譯器逐個編譯C/C++源文件。 編譯器的單次編譯視野僅限于當前C/C++源文件,不能獲知其他源文件的情況,包括全局變量,函數調用,指針別名等關系。 因此編譯器會采用較為保守和安全的優化假設。
IAR Embedded Workbench則為用戶提供了 **“多文件編譯” **功能,如下圖。 編譯器在工程全局級別或者文件組級別,允許一次編譯多個文件,從而增加了編譯視野,可以進行更為深度的編譯優化策略實施,通常能獲得更好的編譯優化效果。
3. 靈活配置編譯優化選項作用域
IAR Embedded Workbench提供了不同作用域的編譯優化選項設置,使用戶能夠更加靈活的進行配置,對不同編譯優化需求的代碼進行分別配置。
? 全局設置:如之前介紹的編譯優化選項設置方法均為全局設置,作用于整個工程范圍。
? 每個文件/每個組的設置:當文件/組中的所有函數必須具有與項目不同的編譯優化設置時,打開文件/組編譯選項界面(在項目管理器選中文件/組,右擊鼠標選擇Options),選擇“Override inherited settings”,如下圖。 然后進行編譯優化設置。
? 單個函數:當某些函數必須具有不同的編譯優化設置時,可以在源代碼中使用 #pragma 關鍵字進行單獨配置,如下例。
4. 鏈接階段優化選項
IAR Embedded Workbench在鏈接階段也提供了相應的代碼優化選項,如下圖。
? 鏈接階段默認消除未使用的變量和函數。
? 小函數內聯(inline small routines):將對小函數的某些調用替換為函數的本體。
? 合并重復段(Merge duplicate sections):鏈接器可以檢測具有相同內容的只讀段,并僅保留每個此類段的一個副本,從而將對任何重復段的所有引用重定向到保留的段。
? C++虛擬函數消除(Perform C++ virtual function elimination):虛函數是 C++ 中的一種特殊函數,它的實際調用取決于對象的實際類型。 虛函數的調用需要運行時動態解析,因此會導致一定的運行時開銷。 “C++虛擬函數消除” 可刪除不需要的虛擬函數和動態運行時類型信息,以減少程序運行時的開銷,提高程序的性能。
嵌入式軟件編譯優化選項配置整體思路
嵌入式系統中通常硬件資源有限,特別是存儲器容量,直接與MCU硬件成本掛鉤,影響整個系統的硬件物料成本; 另一方面,嵌入式軟件又需要對外部信號進行實時響應,對外部設備進行實時控制,比如馬達控制組件; 除此之外,電池供電的嵌入式設備需要具備低功耗特性,要求CPU盡可能處于深度睡眠狀態,以盡可能延長設備的單次電池工作時間。 結合上述情況,對于嵌入式軟件進行編譯優化選項配置需要進行差異化考量,具體如下:
? 對于整個嵌入式軟件項目作用域,可以考慮極致代碼體積優化。 較少的代碼體積可以適配較小flash容量的MCU,從而節省硬件物料成本。
? 對于運行頻度很高的代碼段,可以考慮極致代碼性能優化。 這樣可以使得關鍵代碼在相同CPU速度的情況下,達到更高的實時響應速度。
? 另外,在電池供電的低功耗應用中,CPU一般處在深度睡眠狀態。 通常是間隔一段時間或者外部事件到來,喚醒CPU執行一個任務,然后CPU重新回到深度睡眠狀態。 設備功耗等于CPU深度睡眠的靜態功耗和任務運行的動態功耗之和。 根據MCU硬件電氣特性,其單位時間動態功耗(mA級別)要遠大于單位時間靜態功耗(uA級別)。
對于經常需要喚醒執行的軟件任務,可以考慮極致代碼性能優化。 這樣會減少動態功耗的時間,以達到整體功耗的下降,從而增加設備的電池使用壽命。
注意事項:
? #pragma optimize 只能降低對應函數的優化等級,或者選擇另外一種優化策略。 如果 pragma optimize的優化等級比編譯器選項的優化等級高,那么 pragma optimize命令會被忽略。
? 高優化等級會讓編譯時間變長,同時讓調試變得困難一些(因為高優化等級會讓生成的代碼和源代碼的對應關系沒有那么直接)。 如果在調試過程中發現類似的問題,建議降低優化等級進行調試。
總結
IAR Embedded Workbench是一款業界領先的編譯工具鏈,除了提供卓越的性能之外,還提供了豐富靈活的編譯優化選項配置,以幫助用戶在不同的嵌入式應用需求下,都能找到最佳的嵌入式軟件代碼性能和體積的平衡點。
在下一篇《深入淺出編譯優化選項(下)》中,我們將介紹編譯過程中的優化策略以及如何在IAR Embedded Workbench配置編譯優化微調項(Enabled transformations),讓用戶可以根據代碼需求配置出更加精準的編譯優化策略組合。
審核編輯:湯梓紅
-
嵌入式
+關注
關注
5002文章
18414瀏覽量
291558 -
IAR
+關注
關注
5文章
324瀏覽量
36343 -
優化
+關注
關注
0文章
218瀏覽量
23735 -
代碼
+關注
關注
30文章
4575瀏覽量
67135 -
編譯器
+關注
關注
1文章
1585瀏覽量
48745
原文標題:深入淺出編譯優化選項(上)
文章出處:【微信號:IAR愛亞系統,微信公眾號:IAR愛亞系統】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論