簡體   English   中英

C ++如何確定函數是否具有內聯功能,實際上是?

[英]C++ How to determine if function has capability for being inlined and actually was?

我對C ++中的inline函數有疑問。 我知道類似的問題多次出現在此。 我希望我的有點不同。

我知道當你指定一些inline函數時,它只是編譯器的“建議”。 以防萬一:

inline int func1()
{
    return 2;
}

有些代碼稍后

cout << func1() << endl; // replaced by cout << 2 << endl;

所以那里沒有神秘感,但是這樣的情況呢:

inline int func1()
{
    return 2;
}

inline int func2()
{
    return func1() * 2;
}

inline int func3()
{
    return func2() * func1() * 2;
}

等等...

哪些函數有機會內聯,是否有益以及如何檢查編譯器實際執行的操作?

哪些功能有機會內聯

如果執行內聯的工具(1)可以訪問函數的定義(= body),那么任何和所有函數都有機會被內聯...

是有益的嗎?

......並認為這樣做是有益的。 如今,優化器的工作是確定內聯在哪里是有意義的,對於99.9%的程序,程序員可以做的最好的事情就是遠離優化器的方式。 剩下的幾個案例是像Facebook這樣的程序,其中0.3%的性能損失是一個巨大的倒退。 在這種情況下,手動調整優化(以及分析, 分析分析 )是可行的方法。

如何檢查編譯器實際執行的操作

通過檢查生成的組件。 每個編譯器都有一個標志,使其以“人類可讀”的格式輸出匯編,而不是(或除了)二進制形式的目標文件。


(1)通常,此工具是編譯器,並且內聯在編譯步驟中發生(將源代碼轉換為匯編/目標文件)。 這也是為什么你可能需要使用inline關鍵字來實際允許編譯器內聯的唯一原因:因為函數的定義必須在正在編譯的轉換單元(=源文件)中可見,並且通常這意味着放置函數定義到頭文件中。 如果沒有inline ,如果頭文件包含在多個翻譯單元中,則會導致多重定義錯誤。

請注意,編譯不是可以進行內聯的唯一階段。 啟用整體程序優化(也稱為鏈接時代碼生成)時,一旦創建了所有目標文件,就會在鏈接時再發生一次優化。 此時, inline關鍵字完全無關緊要,因為鏈接可以訪問所有函數定義(否則二進制文件不會成功鏈接)。 因此這是從內聯中獲得最大收益方法,而不必在編寫代碼時考慮它。 缺點是時間:WPO需要時間來運行,對於大型項目,可能會將鏈接時間延長到不可接受的水平(我個人經歷了一個有點病態的情況,即啟用WPO將程序的鏈接時間從7分鍾縮短到46分鍾)。

想象inline因為只有一個提示編譯器,有點像register 舊版本的C ++和C標准。 注意事項, register已被廢棄(在C ++ 17中)。

哪些功能有機會內聯,是否有益

相信您的編譯器可以做出明智的內聯決策。 要啟用某些特定的調用,編譯器需要知道被調用函數的主體。 您不應該關心編譯器是否在線(理論上)。

在實踐中,使用GCC編譯器:

  • 內聯並不總能提高性能(例如,由於CPU緩存問題, TLB分支預測器等等)

  • 內聯的決定取決於許多 優化選項 使用-O3可能比使用-O1更可能發生; 有許多guru選項(如-finline-limit=和其他)來調整它。

  • 注意個別電話是否內聯。 很可能在第123行的某些調用出現如foo(x)被內聯,但是在第456行等其他地方的另一個調用事件(對於同一函數foo )如foo(y)沒有內聯。

  • 調試時 ,您可能希望禁用內聯(因為這使調試更方便)。 這可以通過-fno-inline GCC優化標志(我經常與-g使用,它要求調試信息)。

  • always_inline 函數屬性 “強制”內聯,而noinline阻止它。

  • 如果您使用鏈接時間優化 (LTO)(例如-flto -O2 (或-flto -O3 ))進行編譯和鏈接 ,例如在Makefile使用CXX=g++ -flto -O2 ,則可能會在多個翻譯單元之間進行內聯(例如C ++源代碼)文件)。 但是,LTO至少會使編譯時間翻倍(通常情況下更糟)並在編譯期間消耗內存(因此更好地擁有大量RAM),並且通常只會提高幾個百分點的性能(這個經驗法則有奇怪的例外) 。

  • 您可以以不同方式優化函數,例如使用 #pragma GCC optimize ("-O3")或使用函數屬性 optimize

  • 另請-fprofile-generate 配置文件引導的優化,其中包括-fprofile-generate儀器選項以及使用-fprofile-use和其他優化標志的后一種優化。

如果你g++ -O2 -S -fverbose-asm聯調用(有時候有些調用)很好奇,請查看生成的匯編程序(例如使用g++ -O2 -S -fverbose-asm並查看.s匯編程序文件),或者使用一些內部g++ -O2 -S -fverbose-asm 轉儲選項

代碼的可觀察行為(性能除外)不應該依賴於編譯器的內聯決策。 換句話說,不要指望內聯發生(或不發生)。 如果您的代碼在有或沒有優化的情況下表現不同,則可能是錯誤的。 閱讀有關未定義行為的內容

另請參閱MILEPOST GCC項目(使用機器學習技術進行優化)。

暫無
暫無

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

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