2013-04-26 4 views
6

EDIT: In der Tat hatte ich einen seltsamen Fehler in meinem Timing-Code zu diesen Ergebnissen führen. Als ich meinen Fehler korrigierte, endete die intelligente Version schneller als erwartet. Mein Timing Code sah wie folgt aus:Langsame XOR-Operator

bool x = false; 
before = now(); 
for (int i=0; i<N; ++i) { 
    x ^= smart_xor(A[i],B[i]); 
} 
after = now(); 

ich die ^= getan hatte mein Compiler weg von der Optimierung der for-Schleife zu verhindern. Aber ich denke, dass die ^= irgendwie seltsam mit den beiden XOR-Funktionen interagiert. Ich änderte meinen Timing-Code, um einfach ein Array der xor-Ergebnisse auszufüllen und dann mit diesem Array außerhalb des zeitgesteuerten Codes zu rechnen. Und das fixierte Dinge.

Soll ich diese Frage löschen?

END EDIT

I definiert zwei C-Funktionen ++ wie folgt:

bool smart_xor(bool a, bool b) { 
    return a^b; 
} 

bool dumb_xor(bool a, bool b) { 
    return a?!b:b; 
} 

Mein Timing Tests zeigen, dass dumb_xor() etwas schneller ist (1.31ns vs 1.90ns wenn inlined, 1.92ns vs 2.21ns, wenn sie nicht inline). Dies verwirrt mich, da der ^ Operator eine Einzelmaschinenoperation sein sollte. Ich frage mich, ob jemand eine Erklärung hat.

Die Anordnung sieht wie folgt aus (wenn nicht inlined):

.file "xor.cpp" 
    .text 
    .p2align 4,,15 
.globl _Z9smart_xorbb 
    .type _Z9smart_xorbb, @function 
_Z9smart_xorbb: 
.LFB0: 
    .cfi_startproc 
    .cfi_personality 0x3,__gxx_personality_v0 
    movl %esi, %eax 
    xorl %edi, %eax 
    ret 
    .cfi_endproc 
.LFE0: 
    .size _Z9smart_xorbb, .-_Z9smart_xorbb 
    .p2align 4,,15 
.globl _Z8dumb_xorbb 
    .type _Z8dumb_xorbb, @function 
_Z8dumb_xorbb: 
.LFB1: 
    .cfi_startproc 
    .cfi_personality 0x3,__gxx_personality_v0 
    movl %esi, %edx 
    movl %esi, %eax 
    xorl $1, %edx 
    testb %dil, %dil 
    cmovne %edx, %eax 
    ret 
    .cfi_endproc 
.LFE1: 
    .size _Z8dumb_xorbb, .-_Z8dumb_xorbb 
    .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3" 
    .section  .note.GNU-stack,"",@progbits 

Ich bin mit g ++ 4.4.3-4ubuntu5 auf einem Intel Xeon X5570. Ich habe mit -O3 kompiliert.

+0

Nanosekunde ist wahrscheinlich zu klein, um einen aussagekräftigen Vergleich zu ermöglichen. – yngccc

+2

Möglicherweise müssen Sie Ihren Timing-Code anzeigen. Das ist leicht falsch zu verstehen. –

+2

Ich würde 'a! = B' über 'a?! B: b' bevorzugen. – Pubby

Antwort

4

Vorausgesetzt, dass Ihr "dumb XOR" -Code deutlich länger ist (und die meisten Anweisungen sind abhängig von einer vorherigen, so dass es nicht parallel läuft), vermute ich, dass Sie eine Art von Messfehler in Ihren Ergebnissen haben.

Der Compiler muss zwei Anweisungen für die Out-of-Line-Version von "Smart XOR" erzeugen, da die Register, in die die Daten kommen, nicht das Register sind, das das Ergebnis liefern soll Umzug von EDI und ESI nach EAX. In einer Inline-Version sollte der Code in der Lage sein, das Register zu verwenden, in dem sich die Daten vor dem Aufruf befinden, und wenn der Code dies zulässt, bleibt das Ergebnis in dem Register, in dem es sich befand.

Der Aufruf einer Funktion außerhalb der Leitung ist wahrscheinlich mindestens genauso lange in der Ausführungszeit wie der eigentliche Code in der Funktion.

Es würde helfen, wenn Sie Ihr Testgeschirr showes, die Sie auch für das Benchmarking verwenden ...

5

Ich glaube nicht, dass Sie Ihren Code richtig gebenchmarkt.

Wir können in der generierten Assembly sehen, dass Ihre smart_xor Funktion ist:

movl %esi, %eax 
xorl %edi, %eax 

während dumb_xor Funktion ist:

movl %esi, %edx 
movl %esi, %eax 
xorl $1, %edx 
testb %dil, %dil 
cmovne %edx, %eax 

So offensichtlich, die erste wird schneller sein.
Wenn nicht, dann haben Sie Benchmark-Probleme.

Sie können also Ihren Benchmarking-Code optimieren ... Und denken Sie daran, dass Sie viele Anrufe ausführen müssen, um einen guten und aussagekräftigen Durchschnitt zu erhalten.