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

от автора

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  

ссылка на оригинал статьи https://habr.com/ru/post/560690/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *