[英]Performance of comparisons in C++ ( foo >= 0 vs. foo != 0 )
我最近在編寫一段代碼,其中性能非常重要,基本上我有以下情況:
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循環,因為第一個表達式將為false。
現在的問題是,如果使用之間的性能存在差異
counter > 0
和counter != 0
?
我懷疑會有,有沒有人知道這方面的具體細節。
衡量就是知道。
你認為這將解決你的問題! :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) <----
在編程中,以下陳述是指示地獄之路的標志:
我最近一直致力於一段代碼,其中性能非常重要
以最干凈,最容易理解的方式編寫代碼。 期。
完成后,您可以測量其運行時間。 如果花費的時間太長,請測量瓶頸,加快最大的瓶頸。 繼續這樣做,直到它足夠快。
由於錯誤地強調盲目優化而失敗或遭受災難性損失的項目清單是巨大而悲慘的。 不要加入他們。
我認為你花時間優化錯誤的東西。 “這里代價高昂的其他東西”,“做東西”和“做更多東西”更重要的是要看。 這就是我打賭會帶來巨大性能改進的地方。
如果計數器以負數開頭,將會有很大的不同。 否則,在我熟悉的每個平台上,都沒有區別。
counter > 0
和counter != 0
之間有區別counter != 0
? 這取決於平台。
一種非常常見的CPU類型是我們在PC上的英特爾CPU。 兩個比較都將映射到該CPU上的單個指令,並且我假設它們將以相同的速度執行。 但是,要確定您必須執行自己的基准測試。
正如吉姆所說,如果有疑問,請親自看看:
#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?
}
這是衡量時間的一種非常好的方式。 希望有所幫助。
認為比較的類型會在不知情的情況下產生影響,這就是猜測的定義。
不要猜。
好的,你可以測量一下,當然。 但是,這些類型的比較速度如此之快,以至於您可能會在這一行代碼上看到基於處理器交換和調度的更多變化。
這有點不必要的,過早的優化。 正確的你的程序,優化你看到的。 如果您需要更多,個人資料,然后從那里開始。
我想補充一點,這個代碼在現代cpus上的壓倒性的性能方面將不是由比較指令控制,而是比較是否被很好地預測,因為任何錯誤預測將浪費比任何積分操作更多的周期。
因此,循環展開可能是最大的贏家,但衡量,衡量,衡量。
通常,它們應該是等效的(兩者通常在單周期指令/微操作中實現)。 您的編譯器可能會執行一些奇怪的特殊情況優化,這很難從源級別進行推理,這可能會使一個稍微快一點。 此外,相等性測試比不等式測試(>)更節能,盡管系統級效應非常小,不值得討論。
可能沒有區別。 您可以嘗試檢查每個的程序集輸出。
話雖這么說,判斷任何差異是否顯着的唯一方法是嘗試兩種方式和衡量標准。 我敢打賭,改變對優化沒有任何影響。
假設您正在為x86架構開發,當您查看匯編輸出時,它將歸結為jns vs jne。 jns將檢查符號標志,jne將檢查零標志。 據我所知,這兩項行動同樣代價高昂。
顯然,解決方案是使用正確的數據類型。
使計數器成為unsigned int。 然后它不能小於零。 您的編譯器顯然會知道這一點,並被迫選擇最佳解決方案。
或者你可以測量它。
你也可以考慮如何實現......(這里我們繼續切線)......
當然,計算機是有趣的東西,檢查單個位可能比整個值花費更長的時間(無論你的平台上有多少字節)。
你可以測量一下......
你可以發現它比另一個更優化(在你測量它的條件下)。 但是你的程序仍然會像狗一樣運行,因為你花了所有時間來優化代碼的錯誤部分。
最好的解決方案是使用許多大型軟件公司所做的事情 - 將硬件歸咎於沒有足夠快速運行並鼓勵客戶升級他們的設備(由於您的產品運行速度不夠快,這顯然是劣質的)。
</ rant>
我剛剛在問到這個問題3年后偶然發現了這個問題,所以我不確定答案仍然有多么有用......不過,我很驚訝沒有看到明確表示回答你的問題需要知道兩個而且只有兩件事情:
至於第一點,每個處理器都有不同的測試指令。 在一個給定的處理器上,兩個類似的比較可能會變為采用不同數量的周期。 例如,您可能有一個1周期指令來執行gt(>),eq(==)或le(<=),但沒有1周期指令用於其他比較,如ge(> =)。 在測試之后,您可能決定執行條件指令,或者更常見的是,如在代碼示例中那樣,跳轉。 同樣,跳轉所花費的周期在大多數高端處理器上采用可變數量的周期,這取決於是否采用,預測或未預測條件跳轉。 當您在匯編中編寫代碼並且您的代碼對時間至關重要時,您實際上可能需要花費大量時間來確定如何最佳地安排代碼以最小化整體循環計數,並最終可能需要優化的解決方案基於給定比較返回true或false的時間。
這引出了我的第二點:編譯器,如人類編碼器,嘗試安排代碼以考慮可用的指令及其延遲。 他們的工作比較困難,因為匯編代碼所知的一些假設就像“計數器很小”一樣很難(不是不可能)知道。 對於像循環計數器這樣的普通情況,大多數現代編譯器至少可以識別計數器將始終為正,並且a!=將與a>相同,從而相應地生成最佳代碼。 但是,正如帖子中提到的那樣,你只會知道你是運行測量,還是檢查你的匯編代碼並說服自己這是你在裝配中可以做的最好的。 當您升級到新的編譯器時,您可能會得到不同的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.