VC2017編譯的尺寸優化

blowfish發表於2017-12-07
優化是一種場景相關的權衡,看是速度優先,還是尺寸優先,或者是二者的折衷。在一個手機app動則幾十上百兆而且隔三差五就要耗流量進行升級的今天,PC機上卻還是有需要做exe/dll尺寸優化的場景。最近折騰了一下OpenSSL編譯的裁剪,順帶把VC2017的尺寸優化做一下簡單筆記。

1、首先是/O1(Minimize Size)選項,這個可能會降低程式的執行效率,通常不用,而是用預設的/O2(Maximize Speed)。


2、/arch:IA32(No Enhanced Instructions)。這個是採用古老的386指令集而不生成MMX、AVX等“新”指令,通常生成的程式碼尺寸較小(只是經驗值)。新的指令集,理論上效率要高一些。具體怎麼選擇就是看所要支援的CPU型號。OpenSSL的編譯指令碼“perl Configure VC-WIN32  386"可以指定只使用386指令集,如果不帶386引數,會根據cpuid的檢測結果動態決定採用什麼指令集,也就是會存在多套指令集共存完成同樣的功能,編譯出來的尺寸會大一點。當然,OpenSSL的這個386配置引數,控制它的perl指令碼在預生成優化用的彙編程式碼時採用什麼指令集,但目前並沒給cl.exe增加/arch:IA32引數,所以編譯32位的OpenSSL時需要手動修改ms\nt.mak加上這個引數,以便編譯*.c時只生成386指令集。


3、/Gy(Enable Function-Level Linking)選項。這個是預設的設定,基本上也是必開的項。 這個選項告訴編譯器將一些函式(具體是哪些函式,編譯器自行決定)打包放到單獨的section中,這有個專有名詞叫COMDAT,即common data,意思是打包的函式或者打包的資料。按微軟大拿Raymond Chen的說法,COMDAT這個概念最早來自FORTRAN語言。gcc和llvm對COMDAT都有對應的支援。連結器在連結階段,可以對COMDAT中重複的函式進行消重(folding,摺疊)。如果編譯器不把函式打包成COMDAT項,連結器是不敢貿然優化掉對應的函式的,因為缺少這些函式的引用資訊。


4、/GL(Whole Program Optimization)選項。基本上也是必開的項。告訴編譯器做跨模組的優化。


5、/LTCG(Link-time Code Generation)選項。基本上也是必開的項。進行全域性/跨模組的優化。這個選項有一些子選項是根據試執行的情況來做優化的(Profile Guided Optimization),類似於“開著Xperf跑用例,然後分析Xperf記錄的資料,以決定優化哪裡以及怎麼優化”,只不過是編譯器幫著幹它所能幹的。/LTCG選項開了之後,才能開/GL。


6、/Gw(Optimize Global Data)選項。基本上也是必開的項。/Gy是把函式打包成COMDAT項,而/Gw是把資料打包成COMDAT項,一般是全域性只讀的資料,並且這些資料沒有被程式碼做取地址操作。/Gw是從VC2013開始引入的,微軟最初可能是出於優化自己的產品尺寸的需要,不過也算是體恤碼農了。


7、/OPT:REF(Optimize References)選項。基本上也是必開的項。這個選項把COMDAT中沒被引用的函式、資料都給優化掉,編譯產物的尺寸當然大大減小。前提是已經開了/Gy、/Gw把函式、資料都打包成COMDAT項了。


8、/OPT:ICF(Identical COMDAT Folding)選項。基本上也是必開的項。這個選項把COMDAT中重複的函式、資料都給優化掉,只保留一份,效果也是產物的尺寸減小。前提也是已經開了/Gy、/Gw。開/OPT:REF時,編譯器會自動開一部分/OPT:ICF的功能。另外,由於/OPT:ICF對函式、資料消重了,而如果你的程式碼正好是假定這些被消重的函式、資料的地址不同,那就會出問題,也就是說/OPT:ICF在特定情況下存在一定的副作用,不過我們的程式碼通常不會正好躺槍。


9、__declspec(selectany)編譯指示。告訴編譯器將對應的全域性變數、全域性物件、靜態成員變數等資料打包成COMDAT項。一般不推薦在*.h/*.hpp標頭檔案中定義變數,萬一要定義的話,最好用 __declspec(selectany)修飾一下,方便進行尺寸優化。這個編譯指示相當於一個更細粒度的/Gw選項。


參考:


Introducing ‘/Gw’ Compiler Switch

https://blogs.msdn.microsoft.com/vcblog/2013/09/11/introducing-gw-compiler-switch/


Why is Identical COMDAT Folding called Identical COMDAT Folding?

https://blogs.msdn.microsoft.com/oldnewthing/20161024-00/?p=94575

相關文章