2011-09-18 62 views
13

說我有一些功能,每個代碼大約兩個簡單的線條,和他們互相稱呼這樣的:A電話B電話C調用D ...調用K。 (所以基本上這是一系列短的函數調用。)編譯器通常會在調用樹中嵌入這些函數多深?編譯器內聯函數有多深?

+0

您可以簡單地測試並查看程序集!您的編譯器文檔應該告訴您如何指定內聯深度;我認爲默認情況下GCC的值大概是50。 –

+2

我相信這應該是編譯器特定的,並且不會發布編譯器的信息。 –

+1

在MSVC下,您可以使用'#pragma inline_depth'(http://msdn.microsoft.com/zh-cn/library/cx053bca.aspx)對此進行部分控制,儘管在某些情況下我遇到了問題(例如遞歸內聯,這是有可能的,但從來沒有工作,最終做手工) – Necrolis

回答

12

的問題是沒有意義的。

如果你仔細想想內聯,而其後果,你就會意識到這一點:

  • 避免了函數調用(與所有的寄存器保存/幀調整)
  • 自曝更多背景信息優化(死了商店,死碼,公共子表達式elimintation ...)
  • 重複碼(腹脹指令緩存和可執行文件的大小,除其他事項外)

決定當無論是否內聯,編譯器都會在潛在的膨脹和預期的速度增益之間執行平衡操作。這種平衡行爲受到選項的影響:對於gcc -O3意味着優化速度,而-Oz意味着對尺寸進行優化,在內聯時它們具有準相反的行爲!

因此,重要的不是「嵌套層次」是指令的數量(可能加權因爲不是所有的都是一樣的)。

這意味着,一個簡單的轉發功能:

int foo(int a, int b) { return foo(a, b, 3); } 

是從視點內聯基本上是「透明的」。

另一方面,計算一百行代碼的函數不太可能被內聯。除了一次只調用一次的自由函數是準系統內聯的,因爲它在這種情況下不會造成任何重複。

從這兩個例子,我們得到的啓發是如何表現一種預感:

  • 少的指令功能有,用於inling
  • 的次數越少就越好叫法,內聯
  • 更好

在那之後,他們的參數,你應該能夠設置影響這種或那種方式(MSVC爲__force_inline強烈的inling暗示,gcc因爲他們-finline-limit標誌,以「提高」的tresh舊的指令數等...)


在切線:你知道部分內聯

它是在4.6中的gcc中引入的。顧名思義,這個想法是部分內聯一個功能。大多數情況下,爲了避免函數被「守護」時函數調用的開銷,並且可能(在某些情況下)幾乎立即返回。

例如:

void foo(Bar* x) { 
    if (not x) { return; } // null pointer, pfff! 

    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    foo(x); 
    // DO 2 
} 

可以得到 「優化」 爲:

void [email protected](Bar* x) { 
    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    if (x) { [email protected](x); } 
    // DO 2 
} 

當然,再次爲內聯啓發式申請,但他們更多的申請有差別!


最後,除非你使用WPO(全程序優化)或LTO(鏈接時間優化)功能只能如果他們的定義是相同的TU(翻譯單元)內聯該調用點。

+0

我通常不會這樣做,但我認爲我應該改變接受的答案。 :)我不知道部分內聯,也不知道基於調用次數的內聯。感謝細節。 –

7

我見過編譯器內聯多於5個函數。但在某種程度上,它基本上成爲編譯器所做的空間效率權衡。每個編譯器在這方面都有所不同。 Visual Studio對於內聯非常保守。 GCC(-O3下)和英特爾編譯愛內聯......

+0

IIRC在gcc它取決於一些近似的「指令計數」功能被內聯(即它實際上是多久);嵌套層次不起到我在文檔('-finline-limit'和朋友)中讀取的角色,因爲長度爲10的函數將內嵌與5 +嵌套5相同。 – eudoxos

+1

如果函數被調用只有一次沒有理由避免內聯。如果配置文件反饋說明它應該,GCC也會積極地進行內聯。 –

+3

@贊恩Lynx:大部分是正確的。有些情況下,最好不要內聯。如果函數處於性能關鍵的循環中,並且很少調用(如陷阱處理程序),那麼最好不要內聯它,以便將循環的代碼大小縮小。 (這有時會讓你用短跳而不是長跳) – Mysticial

相關問題