Как стать автором
Обновить

Benchmark CPU's Instructions (just before loading the OS) — XCHG vs XOR, XOR, XOR

Время на прочтение2 мин
Количество просмотров3K
1.225.000 - среднее для XCHG (слева), 1.280.014 - среднее для XOR, XOR, XOR (справа)
1.225.000 - среднее для XCHG (слева), 1.280.014 - среднее для XOR, XOR, XOR (справа)

Возможно не только мне интересно, а каков микрокод инструкции XCHG на RISC для x86 CISC?Например ни для кого не секрет, что на языках высокого уровня, чтобы обменять значениями две переменные "X" и "Y", нужна ещё одна переменная, скажем "Z".

X=5, Y=7
Z=Y
Y=X
X=Z
X=7, Y=5

Но, процессоры это умеют делать командой XCHG, причём, явно никакой третьей переменной здесь вроде бы как и нет...

X=5, Y=7
XCHG X, Y
X=7, Y=5

Я даже предполагал что сама аббревиатура "XCHG", это ни что иное как "XOR CHANGE", сразу скажу что подтверждения этой догадки я нигде не встречал. Почему XOR CHANGE? Возможно потому что обмен между регистрами происходит с участием логической команды XOR.

X=5, Y=7
XOR X, Y
XOR Y, X
XOR X, Y
X=7, Y=5

Что ж, я решил проверить свою теорию, промерив продолжительность исполнения инструкции "XCHG" и её аналога "XOR, XOR, XOR". Ну а чтобы результаты были максимально детерминированными, я решил запустить всё это дело ещё до загрузки какой-либо операционной системы, т.е. сразу после того, как БИОС компьютера решит загружаться с определённого накопителя. В общем для максимальной чистоты эксперимента, я разместил приведённый ниже код прямо в MBR загрузочного диска (в своём случае я использовал флешку).
Следующий код повторяет инструкцию "XCHG EDI, EAX" 7 раз, а инструкцию "XOR" - 21 раз ну и накапливает затраченные тики процессора. Цикл для каждой тестируемой команды повторяется по 10000 раз. После чего всё это прокручивается ещё и ещё (всего 20 раз), в итоге вычисляется среднее. Как по мне, тест получается довольно "чистый", более-менее детерминированный. Ну а что касается того, равны ли по продолжительности исполнения команда XCHG и три команды XOR, то судя по этому тесту, XCHG выполняется на 5% быстрее, что никак не вписывается в мою теорию :)

до этого момента инициализация сегментных регистров + возможные перемещения блоков кода
             mov      ax, 3
             int      10h
             cli                            ; запретим прерывания
             mov      al, 0FFh
             out      021h, al
             out      0A1h, al
             mov      cx, 20                ; сделаем 20 попыток
again:       push     cx
             xor      ebp, ebp
             mov      si, 10000             ; повторим 10000 раз для XCHG
@@:          xor      eax, eax
             xor      edi, edi
             cpuid                          ; заставим ЦПУ выполнить все предыдущие команды
             rdtsc
rept 7     { xchg     edi, eax }            ; повторим 7 раз XCHG
             cpuid
             rdtsc
             sub      eax, edi	            ; вычтем разницу
             add      ebp, eax              ; суммируем результаты
             dec      si
             jnz      @B
             mov      [_xchg], ebp          
             xor      ebp, ebp
             mov      si, 10000             ; повторим 10000 раз для XOR
@@:          xor      eax, eax
             xor      edi, edi
             cpuid
             rdtsc
rept 7     { xor      edi, eax              ; повторим 7 раз по три XOR
             xor      eax, edi
             xor      edi, eax }
             cpuid
             rdtsc
             sub      eax, edi
             add      ebp, eax
             dec      si
             jnz      @B
next:        mov      [_xor], ebp
             mov      eax, [_xchg]
             add      [totalxchg], eax
             mov      di, [screen]
             call     print
             add      word [screen], 32
             mov      eax, [_xor]
             add      [totalxor], eax
             mov      di, [screen]
             call     print
             add      word [screen], 128
             pop      cx
             dec      cx
             jnz      again
             dec      byte [color+1]
             mov      eax, [totalxchg]
             mov      ebx, 20
             xor      edx, edx
             idiv     ebx
             mov      di,[screen]
             call     print
             mov      eax, [totalxor]
             mov      ebx, 20
             xor      edx, edx
             idiv     ebx
             add      word [screen], 32
             mov      di,[screen]
             call     print
@@:          jmp      @B                ; на этом всё.
print:       mov      ebx, 10           ; подпрограмма вывода полученных значений на экран
             xor      cx, cx
more:        mov      si, bufferdec+12
             xor      edx, edx
             sub      si, cx
             idiv     ebx
             add      dl, '0'
             mov      [si], dl
             inc      cx
             test     cl, 1
             je       @F
             test     cl, 2
             je       @F
             or       eax, eax
             je       @F
             mov      [si-1], byte '.'
             inc      cx
@@:          or       eax, eax
             jne      more
color:       mov      ah, 7
             push     0b800h
             pop      es
             mov      si, bufferdec+12
             add      di, cx
             add      di, cx
             std
@@:          lodsb
             stosw
             loop     @b
             push     cs
             pop      es
             ret
screen:      dw 0
_xchg:       dd 0
totalxchg:   dd 0
_xor:        dd 0
totalxor:    dd 0
bufferdec:   db 12 dup 0

rb 510 - ($ - $$)
db 55h,0AAh  
Теги:
Хабы:
Всего голосов 7: ↑6 и ↓1+9
Комментарии11

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань