2012-03-17 79 views
4

我有一個非常性能敏感的應用程序,並且很好奇我是否可以保存一些常量用於鏈接。我使用了一些我正在使用的全局常量(例如模擬尺寸),這些常量被用於瘋狂的量。我試着將它們從常量改變爲變量,性能大幅下降。因此,我創建了一個有點複雜的系統,它從配置文件中分配常量,併爲請求的一組參數顯式構建一個可執行文件。因此,我想盡量減少我爲每個參數更改重建的東西。在鏈接時定義的C常量

問題是如果我可以預先編譯我的一些對象,並將值放在鏈接時間。 我能想到的最可能的實現方式是將那些常量作爲const參數包含在需要它們的函數中,並希望編譯器/鏈接器優化的結果與將其硬編碼爲#define常數的性能相同。有關如何使這項工作的任何建議? (你知道人們如何說「但是這並不重要,除非你在集羣上進行數十億次的科學計算」 - 我是那種在科學中做數十億次的人在羣集上計算是的,在完全實現它之前,我也會對任何東西進行基準測試。)

+0

有什麼不好定義? – BlackBear 2012-03-17 21:30:19

+0

我想在儘可能少地重新編譯時改變它的值。 – zebediah49 2012-03-17 21:47:43

+0

你使用什麼編譯器(和版本)和處理器?較新版本的gcc可以使用LTO(鏈接時間優化http://gcc.gnu.org/wiki/LinkTimeOptimization)來優化編譯代碼,這可能允許您重新編譯一個常量文件。 LTO被引入4.5,並在4.6以後取代IMA,所以我認爲它沒問題。很值得測試和區分反彙編(objdump)文件以瞭解影響。我對你們的發現很感興趣,我的Cortex-M4擁有幾個備用週期 - !) – gbulmer 2012-03-18 00:04:44

回答

4

假設GCC,你可以聲明具有外部鏈接的常量,放在他們自己的源文件和編譯和鏈接與link-time optimizations

在clang的情況下,我推薦一種類似的方法,但不使用常規LTO,而是使用-emit-llvm -c編譯爲位代碼,並且僅在鏈接時作爲最後一步編譯爲本地代碼。

此外,您可以爲-IS(即使用預處理器定義)在ccache和信任,以避免不必要的重新編譯離開你的代碼。

+0

這看起來非常有趣,我相信我正在尋找的東西。我相信我堅持使用GCC 4.1.2(集羣操作系統是一個老的centos幾年前的衍生產品),所以我可能無法在這種情況下使用它,但它仍然非常酷。 – zebediah49 2012-03-18 18:24:14

2

你可以,但它不會真的幫助你。通過使用不同的常量重新編譯所帶來的收益是因爲編譯器在編譯時知道這些值,並可以基於此進行優化。如果你以後建立一個對象並將其與常量數據連接起來,那麼就和使用變量一樣,你會遭受性能影響。

聽起來像一個有趣的問題,目前還沒有真正的毛上身的男子的優化了很多機會,這些天:)

+0

我相信GNU GCC LTO的目的是使鏈接時optimisatiion,優化鏈路就緒代碼,如果編譯器有整個源程序:http://gcc.gnu.org/wiki/LinkTimeOptimization我有*不*測試和測量這一點,但恕我直言,如果所有的LTO給的東西並不比聯變量好這將是根本不值得他們的開發工作。但是,嘿,我一直很失望;-) – gbulmer 2012-03-18 02:42:53

3

你必須分析爲什麼您尋找到有變數,可能是最好的放緩生成的彙編程序,通常是編譯器選項-S

可能有很多原因的加速,如果你有常量:

  • 小整型常量可以去組裝業務
  • 編譯器可以做循環的立即展開
  • 可以有特殊的算術技巧如果常量是2

功率可以得到,另一方面放緩,如果你只有通過指針const您函數和編譯器不能排除您的const限定對象是別名。 const僅表示您沒有權利更改該值,但編譯器無法知道它是否意外更改。這裏用restrict聲明指針可能會有所幫助。

因此,找出故障點,用匯編程序將它們與兩個不同版本(常量和const限定變量)進行比較,並嘗試找出減速的​​原因。

使用inline可以將故障點整齊地優化到位。

如果沒有其他的幫助,如果你碰巧本地化它很好,你甚至可以考慮編寫一個腳本產生該函數與字面常量,並在每次運行之前編譯一小段代碼。如果你的跑步時間很長,那麼編譯和重新鏈接可能會有好處。

+0

+1用於診斷和預編譯。 – 2012-03-18 01:49:22

+0

@Script出口常量,編譯和運行:這是我在做什麼當前,只是軟件的整片 - 是的,甚至有一個相對較長的編譯仍然是值得的。我只是想知道如果我能減少這麼長時間。 – zebediah49 2012-03-18 18:15:22