2010-03-31 88 views
0

說你看到一個循環像這樣的:從緊密內部循環調用小函數的開銷? [C++]

for(int i=0; 
    i<thing.getParent().getObjectModel().getElements(SOME_TYPE).count(); 
    ++i) 
{ 
    thing.getData().insert(
    thing.GetData().Count(), 
    thing.getParent().getObjectModel().getElements(SOME_TYPE)[i].getName() 
    ); 
} 

如果這是Java的我可能會不三思而後行。但是在C++的性能關鍵部分,它使我想要修補它......但是我不知道編譯器是否足夠聰明以至於無用。 這是一個製作的例子,但它所做的只是將字符串插入到容器中。請不要假設任何這些是STL類型,請考慮以下一般性術語:

  • 在for循環中每次或每次都會評估一個混亂的條件嗎?
  • 如果這些get方法只是簡單地返回對象上成員變量的引用,它們是否會被內聯?
  • 您是否期望定製[]運算符得到優化?

換句話說,是否值得將其轉換爲類似的時間(在性能上只,沒有可讀性):

ElementContainer &source = 
    thing.getParent().getObjectModel().getElements(SOME_TYPE); 
int num = source.count(); 
Store &destination = thing.getData(); 
for(int i=0;i<num;++i) 
{ 
    destination.insert(thing.GetData().Count(), source[i].getName()); 
} 

請記住,這是一個嚴密的循環,稱爲百萬次第二。我想知道的是,如果所有這些都會削減每個循環的幾個週期或更重要的東西?


是的我知道關於「過早優化」的引用。而且我知道分析很重要。但是這是關於現代編譯器,特別是Visual Studio的一個更普遍的問題。

+0

我認爲它是無論如何都是有點代碼味道的(「消息鏈」),無論如何,它可能有意義做一些事情。 – UncleBens 2010-03-31 14:42:18

+0

說這是一個「一般性問題」並不會改變這一事實,即這是另一次嘗試優化而無需分析。換句話說,這是一個徒勞無益的猜測。 – 2010-03-31 16:05:40

+0

對不起,你錯了。如果你知道你在做什麼,你應該能夠告訴我這個代碼是否可以被明智地優化,無論花費多少時間。 – 2010-03-31 16:26:07

回答

1

如果循環是關鍵的,我只能建議你看看生成的代碼。如果允許編譯器主動優化呼叫,那麼它可能不會成爲問題。很抱歉地說這個,但現代編譯器可以非常好地優化,我真的會建議分析在你的特定情況下找到最好的解決方案。

4

回答這些問題的一般方法是查看生成的程序集。對於gcc,這涉及用-S替換-c標誌。

我自己的規則是不打對編譯器。如果需要內聯,那麼我確保編譯器具有執行這種內聯所需的所有信息,並且(可能)我試圖通過明確的inline關鍵字來敦促他這樣做。

此外,內聯節省了一些操作碼,但會使代碼增長,就L1緩存而言,這可能會對性能造成很大影響。

2

你所問的所有問題都是編譯器特定的,所以唯一明智的答案是「它取決於」。如果對你很重要,你應該(一如既往)看看編譯器發出的代碼並做一些時間實驗。確保你的代碼是在所有優化開啓的情況下編譯的 - 這對於operator[]()這樣的東西會有很大的改變,這通常是作爲內聯函數實現的,但是不會內聯(至少在GCC中),除非你打開優化。

1

如果方法很小,並且可以並將被內聯,那麼編譯器可以執行與您所做的相同的優化。所以,看看生成的代碼並進行比較。

編輯:將const方法標記爲const也是重要的,例如,在你的例子中count()getName()應該是const讓編譯器知道這些方法不會改變給定對象的內容。

+0

有關const的說明不正確。 const對此不做任何保證。 const可能包含mutables,或者它可能被「拋棄」。 – Suma 2010-03-31 13:33:17

+0

@Suma:是的,但至少它是編譯器的一個提示。也許在實踐中,編譯器忽略優化的const .. – Frunsi 2010-03-31 18:08:02

0

我認爲在這種情況下,您要求編譯器做的事情遠比它合理地給出它可以訪問的編譯時信息的範圍要多。因此,在特定情況下,可能會將雜亂的情況優化掉,但實際上,編譯器沒有特別好的方法來知道您可能從該長串函數調用中會產生哪種副作用。除非我有基準測試(或反彙編),否則我會假設開發測試會更快。

這是JIT編譯器比C++編譯器有很大優勢的情況之一。它原則上可以優化最常見的情況在運行時看到,並提供優化的字節碼(加上檢查,以確保其中一個屬於這種情況)。這種事情總是在多態方法調用中使用,而這些調用實際上並不是多態使用;不管它能否像你的榜樣那樣複雜,但我不確定。

對於它的價值,如果速度真的很重要,我也會把它分成Java。

+0

任何自我尊重JIT的多態內聯緩存將輕鬆優化此示例。雖然原則上靜態C++編譯器可以通過整個程序優化和配置文件反饋來完成PIC,但我不知道有任何生產編譯器會這樣做。 – 2010-04-01 15:39:22

1

作爲一項規則,除非在循環執行過程中結果將要改變,否則通常情況下,您不應該在「for condition」中擁有所有垃圾。

在循環外使用另一個變量集。這會在閱讀代碼時消除WTF,不會對性能產生負面影響,並且會避開功能得到優化的問題。如果這些呼叫沒有優化,這也會導致性能提升。

+0

++我的觀點正好。甚至在我知道這實際上是一個性能問題之前,我會傾向於這樣做。順便說一句,你的自我描述聽起來很有趣。 – 2010-03-31 19:00:46