Ваше утверждение, что один фрагмент быстрее другого, ошибочно.
Если вы посмотрите на код:
mov eax, DWORD PTR [rbp-4]
....
mov DWORD PTR [rbp-4], eax
Вы увидите, что во времени выполнения преобладает загрузка/сохранение в память.
Даже на Skylake это займет минимум 2+2 = 4 цикла.
1 цикл, который sub
или 3 *) циклы, которые занимает and bytereg/add full reg
, просто исчезают во времени доступа к памяти.
На более старых процессорах, таких как Core2, требуется минимум 5 циклов, чтобы выполнить пару загрузки/сохранения по одному и тому же адресу.
Такие короткие последовательности кода сложно рассчитать по времени, поэтому следует позаботиться о том, чтобы у вас была правильная методология.
Также необходимо помнить, что rdstc
не является точным на процессорах Intel и не работает по порядку при загрузке.
Если вы используете правильный код синхронизации, например:
.... x 100,000 //stress the cpu using integercode in a 100,000 x loop to ensure it's running at 100%
cpuid //serialize instruction to make sure rdtscp does not run early.
rdstcp //use the serializing version to ensure it does not run late
push eax
push edx
mov reg1,1000*1000 //time a minimum of 1,000,000 runs to ensure accuracy
loop:
... //insert code to time here
sub reg1,1 //don't use dec, it causes a partial register stall on the flags.
jnz loop //loop
//kernel mode only!
//mov eax,cr0 //reading and writing to cr0 serializes as well.
//mov cr0,eax
cpuid //serialization in user mode.
rdstcp //make sure to use the 'p' version of rdstc.
push eax
push edx
pop 4x //retrieve the start and end times from the stack.
Запустите временной код в 100 раз и возьмите наименьшее число циклов.
Теперь вы получите точный счет с точностью до 1 или 2 циклов.
Вам нужно замерить время пустого цикла. а также и вычтите время для этого, чтобы вы могли видеть чистое время, затраченное на выполнение интересующих инструкций.
Если вы сделаете это, вы обнаружите, что add
и sub
работают с одинаковой скоростью, точно так же, как это происходит в каждом процессоре x86/x64, начиная с 8086.
Это, конечно, также то, что Agner Fog, руководства по ЦП Intel, руководства по ЦП AMD и почти скажем, любой другой доступный источник.
*) and ah,value
занимает 1 цикл, затем ЦП останавливается на 1 цикл из-за частичной записи в регистр, а add eax,value
занимает еще один цикл.
Оптимизированный код
sub DWORD PTR [rbp-4],511
Может быть быстрее, если вам не нужно повторно использовать значение в другом месте, задержка медленная - 5 циклов, но обратная пропускная способность - 1 цикл, что намного лучше, чем в любой из ваших версий.
person
Johan
schedule
19.03.2017