簡體   English   中英

c ++中的高性能代碼(繼承,函數指針,if)

[英]High-performance code in c++ (inheritance, pointers to functions, if)

假設您有一個非常大的圖形,其節點上有大量處理(每個節點有數百萬個操作)。 每個節點的核心例程都是相同的,但是有一些基於內部條件的附加操作。 可以有2個這樣的條件產生4個案例(0,0),(1,0),(0,1),(1,1)。 例如(1,1)表示兩種條件都成立。 條件在程序中建立一次(每個節點獨立設置一個),從那時起,永遠不會改變。 不幸的是,它們是在運行時以完全不可預測的方式確定的(基於通過HTTP和外部服務器接收的數據)。

這種情況下最快的是什么? (考慮到我不知道的現代編譯器優化)

  • 簡單地使用“IF”:if(條件X)執行附加操作X.
  • 使用繼承從基類派生四個類(公開方法OPERATION)以便進行適當的操作並節省數百萬的“ifs”。 [但我不確定這是否真的存在,繼承也必須有其開銷)
  • 使用指向函數的指針根據條件分配一次函數。

我會花很長時間來達到可以自己測試的程度(我還沒有這么大的數據,這將被集成到更大的項目中,因此不容易測試所有版本)。

閱讀答案:我知道我可能要試驗它。 但除了一切,這是一個更快的問題:

數百萬的IF語句和正常的靜態函數調用VS函數指針調用VS繼承,我認為這不是最好的想法在這種情況下,我想從進一步檢查中消除它感謝任何建設性的答案(不是說我不應該關心這些小事;)

除了測量真實數據的實際代碼之外,沒有真正的答案。 有時,在過去,我不得不處理這些問題,而在我實際測量的情況下,虛擬功能比if更快。 但這並不意味着什么,因為我測量的案例與你的案例不同(因此也是一個不同的背景)。 例如,虛函數調用通常會阻止內聯,而if本質上是內聯的,並且內聯可能會打開額外的優化可能性。

我測量的機器處理虛擬功能也很好; 我聽說其他一些機器(例如HP的PA)在實現間接跳轉方面非常無效(不僅包括虛函數調用,還包括函數的返回 - 再次,內聯成本丟失的機會) )。

如果您必須采用最快的方式,並且節點的流程順序不相關,請制作四種不同的類型,每種情況一種,並為每種類型定義一個流程函數。 然后在容器類中,有四個向量,每個節點類型一個。 創建新節點后,獲取創建節點所需的所有數據(包括條件),並創建正確類型的節點並將其推入正確的向量。 然后,當您需要處理所有節點時,按類型處理它們,首先處理第一個向量中的所有節點,然后處理第二個,等等。

你為什么想做這個:

  • 沒有ifs用於狀態切換
  • 沒有vtables
  • 沒有功能間接

但更重要的是:

  • 沒有指令緩存顛簸(你沒有跳到每個下一個節點的代碼的不同部分)
  • 沒有分支預測錯過狀態切換ifs(因為沒有)

即使您具有虛函數的繼承並因此通過vtable進行間接操作,只需在向量中按類型對節點進行排序可能已經在性能方面產生了不同的差異,因為任何可能的指令高速緩存顛簸基本上都會消失並取決於分支預測的方法也可以減少分支預測未命中。

另外,不要制作指針矢量,而是制作一個對象矢量。 如果它們是指針,你有一個額外的地址間接,這本身並不令人擔心,但問題是如果對象幾乎隨機地遍布你的內存,它可能會導致數據緩存顛簸。 另一方面,如果你的對象被直接放入向量中,處理將基本上線性地通過內存,並且緩存將基本上每次都被命中,並且緩存預取可能實際上能夠做得很好。

請注意,如果你沒有正確地進行數據結構創建,你會付出很大的代價,如果可能的話,當向量為你的所有節點立即保留足夠的容量時,每次你的向量用完時重新分配和移動空間會變得昂貴。

哦,是的,正如詹姆斯提到的那樣,永遠都要衡量! 您認為可能是最快的方式可能不是,有時候事情非常直觀,取決於各種因素,如優化,流水線,分支預測,緩存命中/未命中,數據結構布局等。我上面寫的是一個非常一般的方法,但它不能保證是最快的,並且肯定有辦法做錯了。 測量,測量,測量。

使用虛函數的PS繼承大致相當於使用函數指針。 虛函數通常由類頭部的vtable實現,它基本上只是一個函數指針表,用於實現給定虛擬對象的實際類型。 ifs是否比虛擬更快或反過來是一個非常非常難以回答的問題,完全取決於所使用的實現,編譯器和平台。

我實際上對分支預測的有效性印象非常深刻,只有if解決方案允許內聯也可能是戲劇性的。 虛函數和函數指針也涉及從內存加載,可能導致緩存未命中

但是,你有四個條件,所以分支失誤可能是昂貴的。

沒有能力測試和驗證答案真的無法回答。 特別是因為它甚至不清楚這將是一個足以保證優化工作的性能瓶頸。

在這種情況下。 我會在可讀性和易於調試方面犯錯,並與if一起使用

許多程序員已經上課並閱讀了關於某些最喜歡的主題的書籍:流水線,緩存,分支預測,虛函數,編譯器優化,大O算法等等以及這些的性能。

如果我可以對划船進行類比,那么這些就像削減重量,調整力量,調整平衡和精簡,假設你從一些已經接近最佳的快艇開始。

沒關系,你可能實際上是從瑪麗女王開始,你假設它是一艘快艇。

很可能有很多方法可以通過大量因素來加速代碼,只需要減少脂肪(偽裝成好的設計 ),只要你知道它在哪里。 好吧,你不知道它在哪里,並猜測浪費時間在哪里,除非你重視錯誤。

當人們說“測量和使用剖析器”時,他們指向正確的方向,但還不夠遠。 這是我如何做的一個例子,我做 了一個粗略的視頻,FWIW。

除非這些屬性有明確的模式,否則不存在可以為您有效預測此數據相關條件的分支預測器。 在這種情況下,您可能最好避免控制推測(並支付分支錯誤預測的代價),並等待實際數據到達並解決控制流(更可能使用虛函數發生)。 當然,您必須對基准進行驗證,因為它取決於實際模式(例如,如果您甚至有一些類似“標記”元素的小組)。

上面提到的排序很好,但是請注意,它將一個簡單的O(n)問題轉換為O(logn)問題,所以對於大尺寸,除非你可以排序一次 - 多次遍歷,或者否則便宜地保持排序狀態。

請注意,某些預測變量也可能會嘗試預測函數調用的地址,因此您可能會面臨同樣的問題。

但是,我必須同意有關早期優化的評論 - 您是否確定控制流程是您的瓶頸? 如果從內存中獲取實際數據需要更長時間,該怎么辦? 通常,您的元素似乎可以並行處理,因此即使您在單個線程上運行它(如果您使用多個核心,也可以運行更多) - 您應該是帶寬限制而不是延遲限制。

暫無
暫無

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

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