2013-10-16 57 views
2

我正在寫一些代碼,其中速度非常重要。在編寫測試用例之後,我只是轉向編寫主要的二進制文件。對於我的測試跑者,我只是用通配符向鏈接器提供一切。 (如下)編譯器是否會優化未使用的鏈接文件?

在我看來,鏈接是C++將事物粘合在一起的階段 - 填充對函數的引用等,並將二進制文件放在一起。

# Do the linking for the test binary 
$(BIN)test_cases: $(TEST)TestRunner.o 
    $(CC) $(TEST)*.o $(SRC)*.o $(CPPUNITLINKS) $(MAINLINKS) -o $(BIN)test_cases 

我的問題是,因爲我在尋找任何可能的方式來加快我的計劃,我會更好地爲「主」的二進制所需的最低限度的文件鏈接?這會導致更精簡的可執行文件或更快的程序,還是編譯器已經放棄了它不需要的任何有效功能?

+0

我不認爲鏈接所有的obj文件會影響exe的性能 – Matt

+0

應該很簡單,嘗試一個實驗。寫下「hello,world」,鏈接一堆不需要的.objs,看看可執行文件有多大。重複沒有.objs,看看有多大的可執行文件。 – user888379

+0

@ user888379:因爲(在現代操作系統中)整個可執行文件沒有被加載到內存中 - 只有實際使用的部分 - 從一個大的可執行文件中沒有速度的損失。 –

回答

2

將目標文件鏈接到程序時,鏈接程序將解析程序中的任何未解析的符號。如果你想消除死代碼(究竟是不是由默認GCC做),你可以做到以下幾點:

  1. -fdata-sections構建目標文件和-ffunction-sections標誌(參見GCC manual獲取更多信息) ;
  2. 使用-Wl,--gc-sections優化標誌鏈接目標文件,該標誌告訴鏈接器放棄未引用的部分。

注意:只有未使用的static功能被自動剝離。

理論上存在冗餘符號只會影響生成的程序的大小。然而,我發現在剝離死代碼後,人們報告的性能提高了1%到2%。當然代碼庫必須具有相當大的尺寸才能注意到這樣的效果。

請注意,有時這種方法可能無法正常工作。例如,我在某些系統上遇到了崩潰或連接問題,可能是由於執行此功能時出現錯誤。

此外,不要認爲這些標誌在每種情況下都會提高性能和/或尺寸。有很好的理由說明爲什麼這個功能是通過標誌打開的,默認情況下不存在。實際上,有時候鏈接器可能會創建更大的對象和可執行文件和/或更慢的代碼,更不用說您也一定會遇到調試問題。

總之,使用此功能時要非常謹慎,並且始終按照其他答案中的建議在前後分析代碼。

最後,如果你真的在速度之後,你可以檢查my other answer on some useful GCC optimization flags

最後但並非最不重要的,所謂的鏈路時間優化(LTO)是已被引入到GCC,以及最近成爲比較穩定的使用一個巨大的新的和有前途的概念。相應的標誌是-lto,參見herehere瞭解更多信息。雖然現在它可以使用,但並不是所有平臺上的所有東西都有光澤。例如,在Windows上,GCC端口MinGW/MinGW-w64仍然在努力使LTO支持生產質量。

+0

謝謝,我一定會嘗試這個! – joeButler

1

只要文件不是絕對巨大,用於製作二進制文件的文件數量在執行時間中只有很小的作用。當然,如果編譯程序所需的時間是您正在嘗試改進的時間,那麼修剪目標文件的數量可能是實現更快構建時間的一個步驟。

執行程序所花費的時間很大程度上取決於實際執行的代碼。如果您有0,1,3,5,20,100或10000個未被調用的函數不會產生可測量的差異。

理解代碼運行緩慢的原因(如果確實運行緩慢 - 可能只是需要很長時間才能執行所要求的工作)就是使用稱爲分析器的工具。探測器有很多選擇,他們都做基本相同的事情。在最基本的層面上,分析器會告訴你在每個功能上花了多少時間,並且反過來會告訴你在哪裏集中精力。然後,指令分析器將允許您深入查看單個指令,以瞭解編譯器已完成的工作以及在該函數內花費的時間。

1

加速任何程序的第一步是PROFILE。一個好的配置文件將顯示程序中每個函數使用的時間量。

通過分析數據,找到被調用次數最多或花費時間最多的功能。這些是你應該專注於優化的功能。在優化時,根據需求進行優化(例如刪除一些),然後通過設計(選擇不同的算法,刪除函數),然後通過編碼(重寫更高效的代碼,例如減少分支和跳轉),最後通過使用平臺特定的代碼(專用匯編指令)。編碼優化的捷徑是告訴編譯器使用最大速度優化。

如果您要使用動態或共享庫,請將常用函數放入同一個庫中。這允許操作系統只根據需要加載更少的庫。

相關問題