標籤:

C++ 鏈接時間過長,如何找到原因?

C++鏈接時間過長,我想知道是花在什麼地方了,然後針對它進行優化。

補充一下我的具體情況:

1. 硬體環境不考慮,開發機配置蠻好的,用的SSD。

2. 軟體環境是windows7, vs2013.

3. 我們曾經遇到這樣一種情況:

a. 在某個CPP中,調用了大約100個不同class的函數(因為是用宏實現的),當時debug的鏈接時間約為6分鐘,release的鏈接時間達到了15分鐘。

b. 我嘗試新寫一個函數來代替宏(因為這些class都是某個基類的子類,恰好這個函數又是虛方法),debug時間縮短為2分鐘,release時間縮短到3分鐘。對工作流程來說是巨大的優化。

情況大概是這樣:

====================

以前:

#include "A.h"

#include "B.h"

#include "C.h"

...

#define CALL_FUNC(MyClass) {MyClass* pObj = new MyClass; pObj-&>Func();}

CALL_FUNC(A)

CALL_FUNC(B)

CALL_FUNC(C)

...

=====================

優化後:

#include "A.h"

#include "B.h"

#include "C.h"

...

void CallFunc(MyClassBase* pObject)

{

pObject-&>Func();

}

#define CALL_FUNC(MyClass) {MyClass* pObj = new MyClass; CallFunc(pObject);}

CALL_FUNC(A)

CALL_FUNC(B)

CALL_FUNC(C)

c. 事後我分析了一下原因,也許在那個CPP里,因為調用的符號太多,所以導致連接很慢,當我改用一個統一的基類以後,實際上符號就都統一成一個了。

4. Release 的鏈接配置為:

References Yes(/OPT:REF)

Enable COMDAT Folding Yes(/OPT:ICF)

Link Time Code Generation: Use Link Time Code Generation (/LTCG)

最後一個選項貌似很有講究,我也谷歌了一下,不明就裡。也不太清楚release這樣配置鏈接是否合理。


先排除那些硬體問題,比如沒用ssd硬碟,cpu太慢等等,再排除那些不該輕易打開的編譯選項,特別是link time optimization系列,還是慢的話,介紹一個思路。

以前在使用vc的遊戲項目做過一個proj的link時間優化,從9s優化到5s,link時間如何查看可以參考其他同學回復,vc有選項,不贅述。

思路來自這裡,走過路過不要錯過,用力收藏之

http://nedbatchelder.com/blog/200401/speeding_c_links.html

就是減少編譯器生成的export function數量,來降低link時間。經驗教訓就是header文件不要圖方便隨便include。

這裡有些當時的筆記stats,懶得做特別排版了,隨便看看我的具體做法,就是修改代碼,把很多inline函數移掉,或者重新組織項目結構,來加速編譯。

Before Opt:

36462 functions

9.2s

1st Opt:

Remove many inline functions, mainly in meta info system

25710 functions

8.5s

2nd Opt:

Move CommonSkillTable to CommonResource project, thus many inline functions have been moved.

Compiler can save time on resolving unique copies of these functions

13246 functions

6.5s

3rd Opt:

Move QuestTable and BuffTable to CommonResource project

10934 functions

5.9s

4th Opt:

Remove speedtree header file in the QSLevel.h

So many speedtree related functions are removed.

661 Functions left

5.1s


這個問題好像挺少見的,我現在想出來的方式是可以Dump出所有的Symbols(如Linux下的objdump, nm, Windows平台的DumpBin等),然後再進行Symbol分析,如size, count等。


環境說一下,是vs的link還是linux的ld?是debug版還是release版本?關閉各種優化是否依然很慢?磁碟io效率如何?


如果是visual studio:

Tools -&> Options -&> Projects and Solutions -&> VC++ Project Settings -&> Build Timing


說個我遇到的場景:

當你的項目含有多個static library而這些static library又包含了大量重複符號的時候。

比如:lib 1 用了 大量STL , lib 2 也用了 大量STL, 並且都用了很普遍的具現化,例如 std::vector& / std::list& 等等,這時候linker就會很糾結,哎呀相同簽名的符號好多,怎麼辦呢,選一個,然後時間就在糾結中度過了。

最要命的是可能某個class 你圖省事,直接將implementation寫在了h文件里被各種include,那時間就更長了。


Link-Time Optimization(LTO)之類的技術,會在鏈接器被調用的時候,做類似編譯器的工作,而C++的編譯是出了名的慢,結果就是這樣。

解決方法:平時開發時不要打開類似Link-Time Optimization(LTO)之類的技術,只在最後準備發布的時候打開(當然測試工作要保證最後生成的代碼是正確的)。你最後說的Link Time Code Generation(/LTCG)可能就是類似LTO的技術。


盧兄,多給點信息嘛,vs里可以打開鏈接過程查看,不過一切查找終將在ssd里灰飛煙滅


推薦閱讀:

C 語言比 C++ 更強大嗎?
如何評價 C++14 ?
【for(int i=10, j=1; i=j=0; i++, j--)()】將循環幾次?
無編程基礎,跳過C直接學C++,壞處是學習難度陡峭,還是會有知識缺陷,還是二者都有?

TAG:C | 編譯器 |