簡體   English   中英

我什么時候可以自信地用 -O3 編譯程序?

[英]When can I confidently compile program with -O3?

我看到很多人抱怨-O3選項:

我查看 GCC 的手冊:

 -O3 Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions and -frename-registers options.

而且我還確認了代碼以確保兩個選項是-O3唯一包含的兩個優化:

if (optimize >= 3){
    flag_inline_functions = 1;
    flag_rename_registers = 1;
}

對於這兩個優化:

  • -finline-functions在某些情況下(主要是 C++)很有用,因為它允許我們使用 -finline-limit 定義內聯函數的大小(默認為 600)。 設置高內聯限制時,編譯器可能會報告錯誤,抱怨內存不足。
  • -frename-registers試圖通過使用寄存器分配后-frename-registers來避免調度代碼中的錯誤依賴。 這種優化最有利於具有大量寄存器的處理器。

對於inline-function,雖然可以減少函數調用次數,但是可能會導致二進制文件過大,因此-finline-functions可能會引入嚴重的緩存懲罰,甚至比-O2還要慢。 我認為緩存懲罰不僅取決於程序本身。

對於重命名寄存器,我認為它不會對像 x86 這樣的 cisc 架構產生任何積極影響。

我的問題有 2.5 個部分:

  1. 我是否正確地聲稱程序是否可以使用 -O3 選項運行得更快取決於底層平台/架構? [回答]

    編輯:

    第一部分已被確認為真實。 David Hammen 還聲稱,我們應該非常小心優化和浮點運算如何在具有擴展精度浮點寄存器(如 Intel 和 AMD)的機器上進行交互。

  2. 我什么時候可以放心地使用-O3選項? 我想這兩個優化尤其是重命名寄存器可能會導致與 -O0/O2 不同的行為。 我看到一些用-O3編譯的程序在執行過程中崩潰了,這是確定性的嗎? 如果我運行一次可執行文件而沒有任何崩潰,是否意味着使用-O3是安全的?

    編輯:確定性與優化無關,它是一個多線程問題。 但是,對於多線程程序,當我們運行一次可執行文件而沒有錯誤時使用-O3是不安全的。 David Hammen 表明,浮點運算的-O3優化可能會違反用於比較的嚴格弱排序標准。 當我們想使用-O3選項時,還有其他需要注意的問題嗎?

  3. 如果第一個問題的答案是“是”,那么當我更改目標平台或在具有不同機器的分布式系統中時,我可能需要在-O3-O2之間進行更改。 有什么通用的方法可以決定我是否可以通過-O3獲得性能改進? 例如,更多的寄存器,短內聯函數等。 [已回答]

    編輯:第三部分已由 Louen 回答為“平台的多樣性使得對這個問題的一般推理變得不可能”在評估-O3的性能增益時,我們必須同時嘗試並測試我們的代碼以查看哪個更快。

  1. 我看到一些程序在使用 -O3 編譯時崩潰,這是確定性的嗎?

如果程序是單線程的,則程序使用的所有算法都是確定性的,並且如果從運行到運行的輸入相同,則是。 如果這些條件中的任何一個不正確,答案是“不一定”。

如果不使用 -O3 進行編譯,則同樣適用。

如果我運行一次可執行文件而沒有任何崩潰,是否意味着使用 -O3 是安全的?

當然不是。 同樣,如果您不使用 -O3 進行編譯,則同樣適用。 僅僅因為您的應用程序運行一次並不意味着它在所有情況下都能成功運行。 這是使測試成為難題的部分原因。


在浮點寄存器的精度比雙精度高的機器上,浮點運算會導致奇怪的行為。 例如,

void add (double a, double b, double & result) {
   double temp = a + b;
   result = temp;
   if (result != temp) {
      throw FunkyAdditionError (temp);
   }
}

編譯一個未優化使用此add函數的程序,您可能永遠不會看到任何FunkyAdditionError異常。 編譯優化,某些輸入會突然開始導致這些異常。 問題在於,通過優化,編譯器會將temp設為寄存器,而result作為引用,不會被編譯到寄存器中。 添加inline限定符,當您的編譯器使用-O3編譯時,這些異常可能會消失,因為現在result也可以是寄存器。 關於浮點運算的優化可能是一個棘手的主題。

最后,讓我們看一看那些使用 -O3 編譯程序的晚上確實出現問題的情況之一, GCC:程序無法使用編譯選項 -O3 工作 問題只發生在 -O3 上,因為編譯器可能內聯了distance函數,但將結果中的一個(但不是兩個)保存在擴展精度浮點寄存器中。 通過這種優化,某些點p1p2可以導致p1<p2p2<p1評估為true 這違反了比較函數的嚴格弱排序標准。

對於優化和浮點運算如何在具有擴展精度浮點寄存器的機器(例如,Intel 和 AMD)上進行交互,您需要非常小心。

1) 和 3) 你是對的。 有些程序可以從 -O3 啟用的優化中受益,而有些程序則不會。 例如,內聯更多的函數通常更好(因為它繞過了函數調用機制的開銷),但有時它會使事情變慢(例如通過損害緩存局部性)。 這和平台的多樣性使得關於這個問題的一般推理變得不可能。

因此,簡而言之,唯一有效的答案是:同時嘗試兩者,並對您的代碼進行基准測試,看看哪個更快。

2)假設您沒有遇到任何編譯器/優化器錯誤(它們很少見,但確實存在),那么可以合理地假設您的程序中的錯誤僅在 -O3 時出現,那么它可能有一直在那里,只有 -O3 選項發現了它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM