編譯器優化做指令調度時是怎麼考慮不同的微架構下對同一個指令的執行周期數是不同的?
對於同一體系的CPU而言,雖然指令集是相同的,但是不同的micro architecture對同一個指令的執行周期數是不同的。
由於非常多的軟體都是二進位發布的,所以在編譯的時候是無法預見未來運行這個軟體的的micro architecture的。那麼編譯器在在編譯優化階段做指令調度時的評估又是如何根據指令的執行周期數做權重分析的 ?
先佔坑。分靜態編譯和動態編譯兩邊看,然後再看一些實現。
====================================================
靜態編譯
兩種做法:- 只針對一種微架構編譯
- 這「一種」可以是一個代表某種指令集的通用的、虛構的目標。GCC的-mtune=generic就是這類。
- 也可以是針對某個具體CPU微架構的目標。GCC的-mtune=broadwell就是這類。
- 針對多種微架構編譯多份代碼,在運行時經過CPU功能/型號檢測後選擇使用哪一份。如 @vczh的回答所說,Intel編譯器會這樣做,編譯出多份代碼,在運行時通過CPU dispatcher去選擇要使用那一份。參考這個傳送門:Will Intel be forced to remove the "cripple AMD" function from their compiler? - Agner`s CPU blog
以GCC為例,
GCC 4.5.3:https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/i386-and-x86_002d64-Options.htmlGCC 5.1.0:https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/x86-Options.html
可以看到GCC支持-march和-mtune兩個參數,前者用於指定指令集,後者用於指定調優。
====================================================
動態編譯
(回來填坑)
====================================================
編譯器里如何實現細分的平台相關優化
不是所有編譯器都會做細分的平台相關優化。
有些編譯器會根據指令延遲信息來做調度,有些不會。那些會根據指令延遲做調度的,通常會在編譯器里建立簡化的架構描述模型(architecture description model)來描述CPU的一些特徵,例如指令發射寬度、各種資源的個數(多少個加法port、多少個乘法port)、流水線深度、指令的列表、每條指令的使用的資源以及延遲信息等。
以LLVM為例,請看LLVM的target description(.td)文件:lib/Target/X86/X86.td
裡面聲明了許多功能集(feature set),然後有許多不同的調度模型(scheduling model)。CPU的功能檢測(feature detection)主要用於選擇指令集,例如說有沒有SSE2、AVX512支持之類;CPU的具體型號檢測則用於細分的平台相關優化,例如說選擇不同的scheduling model。例如說有針對Haswell的scheduling model:lib/Target/X86/X86SchedHaswell.td
也有通用的scheduling model(GenericModel):lib/Target/X86/X86Schedule.td以GCC為例,它當然也有平台描述文件。請參考官方文檔:16 Machine Descriptions - GCC Internals17 Target Description Macros and Functions - GCC Internalsintel的編譯器會給你的函數編譯出若干份代碼,運行的時候看看你的CPU是什麼而選擇哪一個。對於AMD的CPU,編譯器會認為這是一款最低端的CPU,然後關閉所有高級指令優化,運行最爛的那個編譯結果。
簡單點說是沒辦法。編譯器能做的是對編譯目標平台進行優化。如果運行在非目標平台上,那不保證優化的效果。
其實你可以編譯好多個版本,然後外面用一個簡單的lanucher判斷一下CPU,然後調用對應的版本。
推薦閱讀:
※為什麼北航軟院(5大雙一流軟工之一)每年招幾千個非全日制(雙證)?
※如何看待「大部分程序員只會寫三年代碼」的說法?
※利用hexo搭建自己的博客,為什麼沒有識別出markdown語法?
※為什麼Windows可以運行在不同的硬體環境下?
※編程的時候 命名 方法或變數 詞窮了怎麼辦?