昨天看了 Swift 官方發出的這篇《 Whole-Module Optimization in Swift 3 》,了解了一些 Whole-Module Optimization 的原理。
簡單地說,Whole-Module Optimization(全模塊優化,以下簡稱 WMO),即在編譯項目時,將同屬于一個 Module(可以理解為一個 Target、一個 Package)的所有源代碼都串起來,進行整體的一個分析與優化,區別于 Single-File Optimization(單文件優化,以下簡稱 SFO),WMO 可以更好的統籌全局,去 inline 函數調用、排除死函數(即寫了卻從不調用的函數)等等,大幅優化最終目標文件,使性能提升 2~5 倍。
我對性能的提升沒有疑議,但對其中提到的「編譯時間(Compile Time)」的優化產生好奇。既優化性能,也同時減少編譯時間?于是我做了一個實驗了解了不同的編譯器優化選項的不同效果。
實驗:測試 Optimization Level 在 None(不優化)、SFO、WMO 下分別對編譯速度的影響
實驗對象:基于 Swift 3 的 奇點 for 微博 ,約 24,000 行代碼
實驗方式:在 Debug 模式下分別選擇一檔優化,編譯測試時間。
Xcode 配置:
顯示編譯時間: defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
測試結果:
None 模式(平均 102 秒):
- 97.985s
- 106.039s
- 104.387s
SFO 模式(平均 122 秒):
- 116.114s
- 123.749s
- 126.554s
WMO 模式(平均 89 秒):
- 91.433s
- 87.440s
- 88.465s
可以看到,雖然 WMO 模式是帶優化的,但是它編譯速度確實比不優化的 None 模式還要快,快了 13 秒,接近 15%。而 SFO 顯然最慢,比 None 不優化要慢近 20%。看到這里,官方說的沒錯,WMO 是既優化了性能、又優化了編譯速度的模式,這也是它在新的 Xcode 中成為默認選項的原因。
但是不要高興的太早了,WMO 只是在 Release 模式下成為了默認且推薦的選項,在 Debug 模式下默認依然是 None。那我能不能在 Debug 模式也把優化模式改成 WHO 呢?根據我的測試:能,但最好不要。因為 WMO 沒有把增量編譯優化好,在我的項目里,無論是我是改了一個沒被多方引用的文件的私有函數,還是改了一個被其他文件引用的公開函數,增量編譯都沒能工作——編譯器老老實實地把所有的文件再編譯了一遍,而在 None 和 SFO 下,這些更改帶來的增量編譯通常能在十余秒或更快完成。
在日常開發中,顯然你是不能忍受每次做個小改動然后去測試的時候就要經歷漫長等候的,我想這也正是 Xcode 默認沒把 Debug 模式也開啟 WMO 的原因。
然而,盡管 Xcode 給 Release 模式開啟了 WMO,但事實上我們并不會有太大體驗,一來 Release 是很少頻次的動作,二來平常我們通過 Archive 來發版本,不僅僅會進行標準的 Release build,還會增加一個 Bitcode 的動作(如果項目開啟這個的話),這一切也都使 Archive 整個動作非常慢,WMO 模式減少的編譯時間微乎其微。
但是,無論怎樣,如果你的項目是 Swift 3,Release 下 WMO 沒有開啟的話,那就一定要去開啟,這影響的不僅僅是編譯時間,還有最終目標的運行性能。
圖為開啟 WMO 后編譯目標,只有一個 Compile sources files 的步驟,展開后也沒有一個一個文件的 Compile:
不知道你們的項目在開啟 WMO 后編譯速度提升了多少?
Tags: Swift
文章來源:https://imtx.me/archives/2106.html