Можно, но вряд ли это будет полезно. Маскировка тоже бесполезна в данных обстоятельствах.
Исключения происходят очень медленно, когда они происходят, сначала должно произойти много сложных микрокодированных вещей, прежде чем ЦП даже войдет в обработчик исключений на уровне ядра, а затем он должен также передать их вашему процессу сложным и медленным способом. С другой стороны, они ничего не стоят, если их не происходит.
Но сравнение и ветвь тоже ничего не стоят, пока ветвь предсказуема, а ветвь, которая, по сути, никогда не используется, является. Конечно, их выполнение требует небольшой пропускной способности, но они не находятся на критическом пути... но даже если бы они были, реальная проблема здесь заключается в разделении на каждой итерации.
Пропускная способность этого подразделения в любом случае составляет 1 на 14 циклов (на Haswell - хуже на других µarch), если только fz
не является особенно "хорошим", и даже тогда это 1 на 8 циклов (опять же на Haswell). На Core2 это было больше похоже на 19 и 5, на P4 это было больше похоже (в типичной манере P4) одно деление на 71 такт, несмотря ни на что.
Хорошо предсказанная ветвь и сравнение просто исчезают в этом. На моем 4770K разница между наличием сравнения и ответвлением или отсутствием исчезла в шуме (возможно, если я прогоню его достаточное количество раз, то в конечном итоге получу статистически значимую разницу, но она будет крошечной), причем оба они выигрывают случайным образом около половину времени. Код, который я использовал для этого теста, был
global bench
proc_frame bench
push r11
[endprolog]
xor ecx, ecx
mov rax, rcx
mov ecx, -10000000
vxorps xmm1, xmm1
vxorps xmm2, xmm2
vmovapd xmm3, [rel doubleone]
_bench_loop:
imul eax, ecx, -0xAAAAAAAB ; distribute zeroes somewhat randomly
shr eax, 1 ; increase to make more zeroes
vxorps xmm0, xmm0
vcvtsi2sd xmm0, eax
vcomisd xmm0, xmm1 ; #
jz _skip ; #
vdivsd xmm0, xmm3, xmm0
vaddsd xmm2, xmm0
_skip:
add ecx, 1
jnz _bench_loop
vmovapd xmm0, xmm2
pop r11
ret
endproc_frame
Другая функция была такой же, но две строки, отмеченные знаком #, были закомментированы.
Версия, которая в конечном итоге постоянно выигрывает при увеличении количества нулей, - это версия с ветвью, что указывает на то, что деление на ноль происходит значительно медленнее, чем неправильное предсказание ветвления. Это даже без использования механизма исключения для создания видимого для программиста исключения, это просто из-за стоимости работы микрокодированного "странного исправления случая". Но у вас не так много нулей, так что,
TL;DR особой разницы нет.
person
harold
schedule
06.12.2014
fz
очень маленькое — 1e-30, 1e-100? Не взорвет ли это также ваши расчеты? Разрыв вfz=0
кажется очень странным. - person Alan Stokes   schedule 06.12.2014