2012-08-01 88 views
6

<便宜(快)比<=,同樣,是>便宜(快)比>=哪個運算符更快(>或> =),(<或<=)?

聲明:我知道我可以測量,但那隻會在我的機器上,我不確定答案可能是「具體實現」還是類似的東西。

+12

我猜想他們在大多數架構中都可以編譯成單一指令,但答案是:誰在乎? – meagar 2012-08-01 16:17:50

+1

它們在生成彙編指令方面幾乎相同,如果這就是您要求的。 – 2012-08-01 16:18:04

+8

我明白你的問題背後的精神,但是:你是出於學術興趣問這個問題,還是因爲你認爲這可能會影響你的應用的性能?它不會。如果存在的話,這個差異絕對會被你的應用中的其他因素所淹沒**。不是2或10倍,而是1m或更多。我敢打賭你根本無法衡量它。 – 2012-08-01 16:19:38

回答

3

它有所不同,首先從檢查不同的指令集開始,以及編譯器如何使用這些指令集。以openrisc 32爲例,這顯然是mips的靈感,但條件不同。對於or32有比較和置位標誌指令,比較這兩個寄存器如果小於或等於無符號則設置標誌,比較這兩個寄存器是否相等設置標誌。然後有兩個條件分支指令在標誌集上分支並在標誌清除時分支。編譯器必須遵循這些路徑之一,但少於,少於或等於,大於等等都將使用相同數量的指令,相同的執行時間用於條件分支,相同的執行時間用於不執行條件分支。

現在,對於大多數架構來說,執行分支需要比不執行分支更長的時間,因爲必須刷新並重新填充管道。一些分支預測等可以幫助解決這個問題。

現在一些體系結構的指令大小可能會有所不同,比較gpr0和gpr1與比較gpr0和立即數1234,可能需要更大的指令,例如x86中會看到很多。所以雖然這兩種情況可能是一個分支,如果少於你如何編碼,取決於哪些寄存器碰巧保持什麼值會導致性能差異(當然,x86會做很多流水線處理,大量緩存等來彌補這些問題)。另一個類似的例子是mips和or32,其中r0總是零,它不是一個真正的通用寄存器,如果你寫它,它不會改變,它是硬連線到零,所以比較,如果等於0可能會花費你如果需要額外的指令或兩個指令來填充gpr以使比較可能發生,最壞的情況是必須將寄存器驅​​逐到堆棧或存儲器,釋放註冊立即在那裏,以便可以發生比較。

某些架構,條件執行像手臂,爲全面臂(未拇指)的指令,你可以在每個指令的基礎上執行的,所以如果你有代碼

if(i==7) j=5; else j=9; 

對手臂的僞代碼將是

cmp i,#7 
moveq j,#5 
movne j,#7 

沒有實際的分支,所以沒有管道問題你飛輪通過,非常快。

一個體繫結構到另一個如果這是一個有趣的比較一些提到的,mips或32,你必須專門執行某種比較的指令,其他像x86,msp430和絕大多數每個alu操作改變標誌,手臂等改變標誌,如果你告訴它改變標誌,否則不要如上所示。所以

while(--len) 
{ 
    //do something 
} 

環1減法還設置了標誌,如果在循環中的東西是很簡單的,你可以使整個事情的條件,因此可以節省您的獨立的比較和分支指令並且您在保存管道罰款。 Mips通過比較解決了這一點,並且分支是一條指令,並且它們在分支之後執行一條指令以在管道中保存一點。

一般的答案是你不會看到差異,指令的數量,執行時間等等對於各種條件是相同的。特殊情況下,如小立即比較大的立即數等可能會對角落案例產生影響,或者編譯器可能會根據您做的比較而選擇完全不同。如果您嘗試重寫您的算法以使其給出相同的答案,但使用小於而不是大於等於,則可以更改代碼以獲得不同的指令流。同樣,如果您執行的性能測試過於簡單,編譯器可以/將優化比較完成並僅生成結果,這可能會因您的測試代碼而異,從而導致不同的執行。所有這些的關鍵是反彙編你想比較的東西,看看指令的不同之處。這將告訴你,如果你應該期望看到任何執行差異。

10

TL; DR

似乎有小到無的四大運營商之間的差異,因爲它們都執行大約在同一時間,我(可能在不同的系統,不同的!)。所以,如果有疑問,只需使用對情況最有意義的運算符(特別是在使用C++時)。

所以,事不宜遲,這裏是長的解釋:

假設整數比較:

至於組件產生,結果是依賴於平臺。在我的電腦公司(Apple LLVM編譯器4.0,x86_64的),結果(生成的安裝步驟如下):

a < b (uses 'setl'): 

movl $10, -8(%rbp) 
movl $15, -12(%rbp) 
movl -8(%rbp), %eax 
cmpl -12(%rbp), %eax 
setl %cl 
andb $1, %cl 
movzbl %cl, %eax 
popq %rbp 
ret 

a <= b (uses 'setle'): 

movl $10, -8(%rbp) 
movl $15, -12(%rbp) 
movl -8(%rbp), %eax 
cmpl -12(%rbp), %eax 
setle %cl 
andb $1, %cl 
movzbl %cl, %eax 
popq %rbp 
ret 

a > b (uses 'setg'): 

movl $10, -8(%rbp) 
movl $15, -12(%rbp) 
movl -8(%rbp), %eax 
cmpl -12(%rbp), %eax 
setg %cl 
andb $1, %cl 
movzbl %cl, %eax 
popq %rbp 
ret 

a >= b (uses 'setge'): 

movl $10, -8(%rbp) 
movl $15, -12(%rbp) 
movl -8(%rbp), %eax 
cmpl -12(%rbp), %eax 
setge %cl 
andb $1, %cl 
movzbl %cl, %eax 
popq %rbp 
ret 

這是不是真的告訴我了。所以,我們跳到基準測試:

和女士&先生們,結果在,我創建了以下測試程序(我知道'時鐘'不是計算這種結果的最好方法,但它現在必須要做)。

#include <time.h> 
#include <stdio.h> 

#define ITERS 100000000 

int v = 0; 

void testL() 
{ 
    clock_t start = clock(); 

    v = 0; 

    for (int i = 0; i < ITERS; i++) { 
     v = i < v; 
    } 

    printf("%s: %lu\n", __FUNCTION__, clock() - start); 
} 

void testLE() 
{ 
    clock_t start = clock(); 

    v = 0; 

    for (int i = 0; i < ITERS; i++) 
    { 
     v = i <= v; 
    } 

    printf("%s: %lu\n", __FUNCTION__, clock() - start); 
} 

void testG() 
{ 
    clock_t start = clock(); 

    v = 0; 

    for (int i = 0; i < ITERS; i++) { 
     v = i > v; 
    } 

    printf("%s: %lu\n", __FUNCTION__, clock() - start); 
} 

void testGE() 
{ 
    clock_t start = clock(); 

    v = 0; 

    for (int i = 0; i < ITERS; i++) { 
     v = i >= v; 
    } 

    printf("%s: %lu\n", __FUNCTION__, clock() - start); 
} 

int main() 
{ 
    testL(); 
    testLE(); 
    testG(); 
    testGE(); 
} 

其中,我的機器(帶-O0編譯)上,給了我這個(5次獨立運行):

 
testL: 337848 
testLE: 338237 
testG: 337888 
testGE: 337787 

testL: 337768 
testLE: 338110 
testG: 337406 
testGE: 337926 

testL: 338958 
testLE: 338948 
testG: 337705 
testGE: 337829 

testL: 339805 
testLE: 339634 
testG: 337413 
testGE: 337900 

testL: 340490 
testLE: 339030 
testG: 337298 
testGE: 337593 

我認爲,這些運營商之間的差異是次要的,在最好的,不要在現代計算機世界中不佔重要地位。

+3

彙編代碼實際上告訴了很多。這是說,所有這些片段必須完全相同,所有情況都是平等的。 'setcc'需要1個週期(P4除外,需要3個週期),而不管cc是什麼。但這又如何相關?比較運算符幾乎從不以這種方式使用 - 比較'jcc'的性能(不管cc是什麼)似乎更合理。 – harold 2012-08-01 17:15:53

+1

我第二@harold。程序集講述了很多 - 所有的比較都是使用相同的'cmpl'指令完成的,它比較了它的參數。基本上它從第一個參數中減去第二個參數(丟棄結果),ALU設置標誌寄存器中的相應位。然後可以對這些進行測試,根據或用於設置內存/寄存器值。 – 2012-08-01 18:17:26

+1

@harold他大概的意思是「它不會告訴_me_多」 – hirschhornsalz 2012-08-01 18:43:33

相關問題