2009-09-01 103 views
2

我已經工作了一段代碼最近在性能是非常重要的,而且基本上我有以下的情況(FOO> = 0與富!= 0):性能用C++比較

int len = some_very_big_number; 
int counter = some_rather_small_number; 

for(int i = len; i >= 0; --i){ 
    while(counter > 0 && costly other stuff here){ 
     /* do stuff */ 
     --counter; 
    } 
    /* do more stuff */ 
} 

所以在這裏我有一個循環,運行非常頻繁,對於一定數量的運行,while代碼塊將被執行,直到變量counter減少到零,然後將不會調用while循環,因爲第一個表達式將會假。

現在的問題是,如果使用
counter > 0counter != 0之間的性能有差異嗎?
我懷疑會有,有沒有人知道關於這方面的具體情況。

+0

我覺得第二個while循環應該是for循環。這一改變對性能沒有影響。 – Brian 2009-09-01 21:28:07

+0

即使有區別,它可能是......說1個時鐘週期?這是否真的會改變你的結果... – DeusAduro 2009-09-01 23:15:10

+0

技術上來說是的。 :) – GManNickG 2009-09-01 23:19:26

回答

19

你認爲這會解決你的問題嗎? :D

if(x >= 0) 
00CA1011 cmp   dword ptr [esp],0 
00CA1015 jl   main+2Ch (0CA102Ch) <---- 
... 
    if(x != 0) 
00CA1026 cmp   dword ptr [esp],0 
00CA102A je   main+3Bh (0CA103Bh) <---- 
+0

我得到的輸出是jg和jne而不是jl和je,但它們是洗滌劑。執行這些指令的時間是相同的。 – KFro 2009-09-01 21:05:08

+0

@KFro你在用什麼編譯器?我正在使用VC2008(默認釋放模式) – AraK 2009-09-01 21:05:19

+7

只是爲了擴大一點,在x86中'je'和'jl'根據標誌跳轉。但是,在兩種情況下,標誌都由「cmp」生成,所以*計算*具有相同的性能。基於不同標誌的*決策*也將具有相同的等待時間,因爲標誌已經可用,並且無論如何對所有標誌並行檢查標誌是並行的。 – 2009-09-01 21:05:44

33

要測量就知道了。

+0

有史以來最好的答案:) – zebrabox 2009-09-01 21:10:48

+1

我想不同意,但我必須去找一個首先更好。 – 2009-09-01 21:43:30

+0

我會寫這個「tias」。 – jrockway 2009-09-01 23:20:17

0

一般而言,它們應該是等價的(兩者通常都是在單週期指令/微操作中實現的)。您的編譯器可能會做一些奇怪的特殊情況優化,這很難從源代碼級推理出來,這可能會使得其中一個稍微快一點。而且,平等測試比不平等測試(>)更節能,但系統級別的影響太小而不值得討論。

0

可能沒有區別。您可以嘗試檢查每個組件的輸出。

這就是說,判斷是否有顯着差異的唯一方法是嘗試兩種方式和措施。我敢打賭,這種改變對優化沒有任何影響。

8

我認爲你花時間去優化錯誤的東西。 「這裏昂貴的其他東西」,「做東西」和「做更多東西」更重要。那就是你可以做出我敢打賭的重大績效改進的地方。

3

counter > 0counter != 0之間有區別嗎?這取決於平臺。

一個非常常見的CPU類型是那些來自英特爾,我們在我們的PC。兩種比較都將映射到該CPU上的單個指令,我假設它們將以相同的速度執行。但是,要確定您必須執行您自己的基準。

1

好的,你可以衡量這一點,當然。但是,這種比較速度非常快,您可能會看到更多基於處理器交換和調度的變體,然後在這一行代碼中。

這種不必要的,過早的優化的氣味。正確執行程序,優化你所看到的內容。如果你需要更多,簡介,然後從那裏去。

19

在編程時,下面的語句是符號指定通向地獄的道路:

我已經工作了一段代碼最近在性能是非常重要的

編寫代碼以最乾淨,最容易理解的方式。期。

一旦完成,您可以測量其運行時間。如果時間過長,措施瓶頸,加快最大的。繼續這樣做,直到它足夠快。

因錯誤地強調盲目優化而失敗或遭受災難性損失的項目清單龐大且悲慘。不要加入他們。

+0

您的建議可能適用於一般情況,但在這種情況下,無論採用哪種寫法,清晰度和可讀性都沒有區別。此外,代碼*對性能非常敏感(我碰巧知道它......),實際上這個項目的整個目標是擠壓CPU的每一個最後的性能(並且包括緊密循環中的微優化) 。 – 2009-09-02 08:51:31

+0

我注意到,雖然你確信這個循環對性能至關重要,但你並沒有寫過你通過測量發現這一點。那麼你怎麼知道? – sbi 2009-09-02 13:28:18

+0

如果你知道的很好,但你仍然需要測量。這可能是因爲你正在浪費時間試圖找出如何在一個循環中保存60個CPU週期,其中有60,000個週期可以保存在別的地方。 – 2009-09-02 13:37:13

4

將會有一個巨大的區別如果計數器以負數開頭。否則,每一個平臺我熟悉的,不會有差別。

3

正如吉姆說,有疑問時看到自己:

#include <boost/date_time/posix_time/posix_time.hpp> 
#include <iostream> 
using namespace boost::posix_time; 
using namespace std; 
void main() 
{ 
    ptime Before = microsec_clock::universal_time(); // UTC NOW 
    // do stuff here 
    ptime After = microsec_clock::universal_time(); // UTC NOW 
    time_duration delta_t = After - Before; // How much time has passed? 
    cout << delta_t.total_seconds() << endl; // how much seconds total? 
    cout << delta_t.fractional_seconds() << endl; // how much microseconds total? 
} 

這裏的測量時間的一個非常漂亮的方式。希望有所幫助。

+0

這個問題是他的「做東西」是一個布爾比較。這兩個對universal_time()的調用很可能比被測量的要長得多。即使您將呼叫更改爲RTDSC指令,加上數學可能需要更長的時間。任何以這種方式進行的測量都容易產生噪音。 – 2009-09-02 16:33:18

0

假設您正在爲x86架構開發,當您查看程序集輸出時,它會歸結爲jns vs jne。 JNS將檢查符號標誌和JNE將檢查零標誌。據我所知,這兩項行動都是同樣昂貴的。

1

我想補充一點,在現代CPU的代碼的壓倒性性能方面將通過比較指令不佔主導地位,但是否比較很好地預測因爲任何錯誤預測會浪費更多的週期比任何積分操作。

由於這樣的循環展開可能是最大的贏家,但衡量,測量,測量。

2

認爲在不知道它的情況下比較類型會產生變化的是猜測的定義。

不要猜測。

0

顯然解決方案是使用正確的數據類型。

使計數器成爲一個unsigned int。那麼它不能小於零。您的編譯器顯然會知道這一點,並被迫選擇最佳解決方案。

或者您也可以衡量它。符號位將被設置,所以需要檢查1:

你也可以考慮一下它是如何實現......(在這裏我們去一個切線)...

    小於零
  • 等於零:整體價值將爲零,所以需要檢查所有的位

當然,電腦是有趣的事情,它可能需要更長的時間來檢查比全值的單位(無論您的平臺上有多少字節)。

你可能只是衡量它...

而且你可以找出一個比另一個更優化(的條件下測得的,你的話)。但是你的程序仍然會像狗一樣運行,因爲你花費了所有時間來優化代碼的錯誤部分。

最好的解決方案是使用許多大型軟件公司所做的 - 將硬件歸咎於不能夠快速運行,並鼓勵客戶升級他們的設備(由於產品運行速度不夠快,這顯然較差)。

< /咆哮>

0

我碰到這個問題,跌跌撞撞剛纔,3年有人問後,所以我不知道答案是多麼有用仍然會......不過,我很驚訝沒有看到明確指出,在回答您的問題需要了解兩兩,只有兩件事情:

  1. 你的目標
  2. 您與哪些編譯器,處理器

第一點,每個處理器都有不同的測試說明。在一個給定的處理器上,兩個類似的比較可能會變成不同的週期數。例如,您可能有1個週期的指令來執行gt(>),eq(==)或le(< =),但是沒有其他比較(如ge(> =))的單週期指令。在測試之後,您可以決定執行條件指令,或者更經常地,如您的代碼示例中所示,跳轉。再次說明,在跳轉中花費的週期在大多數高端處理器上需要可變數量的週期,具體取決於是否採用,預測或不預測條件跳轉。當您在彙編中編寫代碼並且代碼時間緊迫時,實際上可能需要相當多的時間來弄清楚如何最好地安排代碼以最大限度地減少整個循環次數,並且最終可能需要一個可能需要優化的解決方案根據給定比較返回真或假的次數。

這將我引向第二點:編譯器與人類編碼器一樣,嘗試安排代碼以考慮可用指令及其延遲。他們的工作比較困難,因爲彙編代碼會知道「計數器很小」這樣的假設很難(不可能)知道。對於像循環計數器這樣的微不足道的情況,大多數現代編譯器至少可以識別出計數器總是正數,並且a =與a相同,因此可以相應地生成最佳代碼。但是,正如帖子中提到的那樣,只有在運行測量或檢查彙編代碼並說服自己這是組裝過程中最好的時候纔會知道。當你升級到新的編譯器時,你可能會得到不同的答案。