2013-04-26 5 views
6

EDIT: Действительно, у меня была странная ошибка в коде времени, приводящем к этим результатам. Когда я исправил свою ошибку, смарт-версия оказалась быстрее, чем ожидалось. Мой код времени выглядел следующим образом:Оператор Slow XOR

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

я сделал ^= препятствовать мой компилятор от оптимизации для-петли прочь. Но я думаю, что ^= как-то странно взаимодействует с двумя функциями xor. Я изменил код времени, чтобы просто заполнить массив результатов xor, а затем выполнить вычисление с этим массивом за пределами запрограммированного кода. И это фиксированные вещи.

Должен ли я удалить этот вопрос?

END EDIT

Я определил две функции C++ следующим образом:

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

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

Моих тестов синхронизации показывает, что dumb_xor() немного быстрее (1.31ns против 1.90ns когда встраиваемая, 1.92ns против 2.21ns когда не встраиваемый). Это меня озадачивает, поскольку оператор ^ должен быть одиночной машиной. Мне интересно, есть ли у кого объяснения.

сборка выглядит следующим образом (если не встраиваемый):

.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 

Я использую г ++ 4.4.3-4ubuntu5 на Intel Xeon X5570. Я скомпилирован с -O3.

+0

Наносекунда, вероятно, слишком мала, чтобы провести какое-либо содержательное сравнение. – yngccc

+2

Возможно, вам потребуется показать свой код времени. Это легко ошибиться. –

+2

Я бы предпочел 'a! = B' над' a?! B: b'. – Pubby

ответ

4

Учитывая, что ваш код «немой XOR» значительно длиннее (и большинство инструкций зависит от предыдущего, поэтому он не будет работать параллельно), я подозреваю, что у вас есть какая-то ошибка измерения в ваших результатах.

Компилятор должен будет подготовить две инструкции для версии «умного XOR» вне очереди, поскольку регистры, в которые поступают данные, не являются регистром, чтобы дать результат возврата, поэтому данные должны переход от EDI и ESI к EAX. В встроенной версии код должен иметь возможность использовать любой регистр данных, находящийся перед вызовом, и если код позволяет это, результат остается в регистре, в который он пришел.

Вызов функции вне линии, вероятно, по меньшей мере такой же продолжительности в времени выполнения, что и фактический код в функции.

Это поможет, если вы showes ваш тест-Жгут, который используется для сравнительного анализа тоже ...

5

Я не думаю, что вы протестировали код правильно.

Мы можем видеть в создаваемой сборке, что ваша smart_xor функции является:

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

dumb_xor пока ваша функция:

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

Так очевидно, что первые из них будет быстрее.
Если нет, то у вас есть проблемы с бенчмаркингом.

Итак, вы можете настроить свой бенчмаркинг. И помните, что вам нужно будет запустить много вызовов, чтобы иметь хорошее и значимое среднее значение.