Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 [ 63 ] 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

Обратная операция генерирует два мопа. Первый (порт 2) загружает значение, считы-вая указатель на стек и записывая значение в регистр. Второй моп (порт О или 1) коррек, тирует указатель на стек, читая и модифицируя его.

6.16.2.5. Вызов. Ближний вызов генерирует 4 мопа (порты 1, 4, 3, 01). Первые два мопа читают указатель на инструкцию (EIP), который не учитывается, потому что он не может быть переименован. Третий моп читает указатель на стек. Последний моп читает и модифицирует его.

6.16.2.6. Возврат. Ближний возврат генерирует 4 мопа (порт 2, 01, 01, 1). Первый моп считывает ESP. Третий читает и модифицирует его.

6.17. Изменение порядка выполнения инструкций (РРго,Р2иРЗ)

Буфер перегруппировки вмещает 40 мопов. Каждый моп ждет в ROB, пока все операнды не будут готовы и не появится свободный модуль для его выполнения. Это делает возможным изменения порядка выполнения кода. Если часть кода задерживается, напрмер, из-за загрузки данных в кэш, это не повлияет на выполнение других частей кода, независимых от предыдущей.

Операции записи в память не могут быть выполнены по порядку, если они зависят от других операций записей. Есть четыре буфера записи, можно ожидать больших потерь производительности во время такой записи в память или записи в некэшированную память. Поэтому рекомендуется делать четыре записи за раз и быль увереным в том, что у процессора есть, чем еще заняться, прежде чем нафузить его еще четырьмя записями Чтение из памяти и другие инсфукции могут выполняться не по порядку, кроме IN, OUT и синхронизирующих операций.

Если код пишет в память по какому-то адресу, а вскоре считывает оттуда же, тогда чтение по ошибке может быть произведено до записи, потому что ROB не имеет понятия об адресах во время перефуппировки. Эта ошибка устанавливается, когда вычисляется адрес, поэтом; операция чтения в таком случае выполняется снова. Потери при этом составляют 3 такта. Единственный путь избежать этого - убедиться, что модуль выполнения будет чем-нибудь занят между последовательными записью в память и чтением из нее по тому же адресу.

В процессорах семейства Pentium имеется несколько модулей выполнения, сгруппированных вокруг пяти портов. Порт О и 1 - для арифметических операций. Простые пересылки, арифметические и логические операции попадают в порт О или 1 в зависимости от того, какой из них свободен. Порт О также обрабатывает умножение, деление, целочисленные побитовые сдвиги и операции с плавающей запятой. Порт 1 в дополнение к основным функциям занимается переходами и некоторыми операциями ММХ и ХММ-Порт 2 обрабатывает все чтения из памяти и некоторые сфоковые операции. В разд. 6-2

jO«ho найти полный список мопов, генерируемых инсфукциями с указанием того, g какой порт они попадают. Следует обратить внимание, что все операции записи в память требуют два мопа, один для порта 3, а другой для порта 4, в то время как операции чтения из памяти фебуют только один моп (порт 2).

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

При оптимизации в 3 мопа за такт следует убедиться, что никакой порт не получает больше одной фети мопов. Следует использовать таблицу мопов в разд. 6.29 для подсчета, сколько мопов попадет в каждый порт. Если порты О и 1 перефужены, в то время как порт 2 свободен, можно улучшить код, заменив некоторые пересылки вида "регистр, регисф" или "регисф, числовое значение" на пересылку вида "регистр, память", чтобы перенести часть нафузки с портов О и 1 на порт 2.

Большинство мопов занимают один такт Гфи выполнении, операции умножения, деления и большинство операций с плавающей запятой занимают больще времени.

Сложения и вычитания с плавающей запятой занимают 3 такта, но модуль выполнения полностью конвейеризован, поэтому он может принимать новые FADD и FSUB каждый такт, пока предыдущие инсфукции выполняются (конечно, если они независимы друг от друга).

Целочисленное умножение занимает 4 такта, умножения с плавающей запятой - 5, умножения ММХ - 3 такта. Умножения целых чисел и ММХ конвейеризованы, поэтому они могут получать новые инсфукции каждый такт. Умножения чисел с плавающей запятой частично конвейеризованы: модуль выполнения может получать новую инсфукцию FMUL через два такта после получения предыдущей, поэтому максимальная производительность будет равна одному FMUL за каждые два такта. "Дыры" между FMULaMH нельзя заполнить целочисленными умножениями, так как они используют ту же схему. Сложения и умножения ХММ занимают 3 и 4 такта соотвественно и полностью конвейеризованы. Но так как каждый регистр ХММ представлен в виде двух 64-битных регисфов, упакованная инсфукция ХММ будет состоять из двух мопов, а производительность будет равна одной арифметической инсфук-ЩЩ ХММ каждые два такта. Инсфукции сложения и умножения ХММ могут выполняться параллельно, потому что они не используют одни и те же порты.

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

Инсфукции переходов, вызовов и возвратов также не полностью конвейеризованы. Нельзя выполнить новый переход в первом же такте после предыдущего. Поэтому максимальная производительность для переходов, вызовов и возвратов равна одному за каждые два такта.



Желательно избегать инструкций, которые генерируют много мопов. Например, инструкцию LOOP XX лучше заменить на DEC ЕСХ / JNZ XX.

Для двух последовательных РОР-инструкций, можно сделать следующую замену:

POP ЕСХ / POP ЕВХ / POP ЕАХ ; можно заменить на:

MOV ЕСХ, [ESP] / MOV EBX,[ESP+4] / MOV ЕАХ,[ESP] / ADD ESP,12

Первая группа команд генерирует 6 мопов, вторая - 4 и декодируется быстрее. Делать то же самое с инструкциями PUSH менее выгодно, поскольку результирующий код будет генерировать задержки чтения регистров, если только нет других инструкций которые можно вставить между ними, или какие-то регистры не были переименованы раньше. Делать подобное с инструкциями CALL и RET означает мешать npabnnbhomv предсказанию перехода. Также следует обратить внимание, что ADD ESP может вызывать задержку AGI в более ранних моделях процессоров.

6.18. Вывод из обращения (РРго, Р2 и РЗ)

Вывод из обращения (retirement) - это процесс, когда временные регистры, исполь зуемые мопами, копируются в постоянные регистры. Когда мои выполнен, он помечае ся в ROB как готовый к выводу из обращения.

Станция вывода из обращения может обрабатывать три мопа за такт. Может пек; заться, что здесь нет никакой проблемы, потому что вывод уже ограничен в RAT тре\ мопами за такт. Тем не менее, вывод из обращения может стать узким местом по дву причинам. Во-первых, инструкции должны выводиться из обращения по порядку. Ecj моп был выполнен не по порядку, то он не может быть выведен из обращения, пока в( мопы, предшествующие ему по порядку, не будут выведены из обращения до него.

И второе ограничение - то, что переходы должны быть выведены из обращен! в трех первых слотах станции. Как декодеры, D1 и D2 могут быть неактивны, если сл. дующая инструкция помещается только в DO, последние два слота станции вывода i обращения могут быть неактивны, если следующий мои, который должен быть вевед( из обращения, - это вычисленный переход. Это существенно в случае короткого цикл число мопов в котором не кратно трем.

Все мопы находятся в буфере перефуппировки (ROB), пока они не будут изъяты i обращения. ROB вмещает 40 мопов. Это устанавливает ограничение на количество инс рукций, которые могут быть выполнены во время большой задержки, вызванной, напр1 мер, делением или другой медленной операцией. Прежде чем будет закончено деленИ-ROB будет заполнен выполняющимися мопами, ожидающими своего изъятия из обр щения. Только когда деление будет закончено и изъято, последующие могут сами нача изыматься из обращения, потому что этот процесс должен выполняться по порядку.

В случае предварительного выполнения предсказанных переходов (см. раздел б--предварительно выполненные мопы не могут быть изъяты из обращения, пока npouec* не проверит, что предсказание верно. В противном случае предварительно выполненН мопы сбрасываются без изъятия из обращения.

,.r:i/..°"J...f. семейства Pentium

Следующие инструкции не могут быть предварительно выполнены: запись в память, 1», OUT и синхронизирующие операции.

6.19. Частичные задержки (РРго, Р2 и РЗ) 6.19.1. Частичные задержки регистра

Частичная задержка регистра - это проблема, которая возникает, когда осуществляется запись в часть 32-битного регистра, а затем чтение из всего регистра или его большей части.

MOV AL, BYTE PTR [MB]

MOV EBX, EAX ; частичная задержка регистра

Происходит задержка в 5 - 6 тактов. Причина состоит в том, что в соответствие AL был поставлен временный регистр (чтобы сделать его независимым от АН). Модулю выполнения приходится ждать, пока запись в AL не будет выведена из обращения, прежде чем станет возможным соединить значение AL с тем, что находится в остальной части ЕАХ. Задержку можно избежать, изменив код, поменяв код так:

MOVZX ЕВХ, BYTE PTR [МЕМ8] AND ЕАХ, OFFFFFFOOh OR EBX, EAX

Можно избежать частичной задержки, поместив другие инструкции после записи, чтобы у последней было время на вывод из обращения до того, как начнется чтение из полного регистра.

Нужно остерегаться частичных задержек, в смешанных операциях с данными 8,16 и 32 бит.

MOV ВН, о

ADD ВХ, АХ ; задержка

INC ЕВХ ; задержка

Не бывает задержки при чтении части регистра после записи в целый регистр или его большую часть.

MOV ЕАХ, [МЕМ32 ADD BL, AL ADD ВН, АН MOV cx, AX MOV DX, BX

нет задержки нет задержки нет задержки задержка

Самый легкий путь избежать частиных задержек - это всегда использовать полные регистры и использовать MOVZX или MOVSX при чтении из операндов более мелкого

Мера. Эти инструкции выполняются очень быстро на РРго, Р2 и РЗ, но существенно дленно на более ранних процессорах. Для получения приемлемой производительности

всех процессорах существует разумный компромисс: MOVZX EAX,BYTE PTR [М8].



XOR ЕАХ, ЕАХ MOV AL, BYTE PTR

Процессоры РРго, Р2 и РЗ делают специальное исключение для этой комбинации, поэтому при последующем чтении из ЕАХ задержки не возникнет. Происходит это потому, что регистр помечается как пустой, когда он ХОКится сам с собой. Процессор помнит, что верхние 24 бита равны нулю и за счет этого избегается задержка. Этот механизм работает только со следующими комбинациями:

EAX,

EBX,

EAX,

EBX,

EBX,

нет задержки

нет задержки

задержка

нет задержки

задержка

нет задержки

Установка регистра в ноль вычитанием его из самого себя работает так же, как XOR, но обнуление регистра с помощью инструкции MOV не предотвращает задержку., Вы можете установите XOR снаружи цикла.

XOR ЕАХ, ЕАХ

MOV ЕСХ, 100 .LL: MOV AL, [ESI]

MOV [EDI], ЕАХ , ; задержка

INC ESI

ADD EDI, 4

DEC ЕСХ

JNZ LL

Глава 6. Оптимизация для процессоров семейства Pentium

Процессор помнит, что верхние 24 бита ЕАХ равны нулю, пока не происходит вызов обработчика прерывания, неправильного предсказания перехода или другого синхронизирующего события.

Следует помнить, что необходимо нейтрализовывать возможные частичные задержки регистра выщеописанным способом при вызове процедуры, которая будет выполнять) команду PUSH с полным регистром.

ADD BL, AL MOV [MEMS], BL XOR EBX, EBX CALL HighLevelFunction

нейтрализируем BL

Больщинство языков высокого уровня выполняют PUSH ЕВХ в начале процедуры, что в выщеприведенном примере приводило бы к частичной задержке регистра, если бы ее не нейтрализовали.

Обнуление регистра с помощью XOR не устраняет его зависимость от предыдущих инструкций.

DIV ЕВХ

MOV [мЕм;

MOV ЕАХ, О XOR ЕАХ, ЕАХ MOV AL, CL ADD ЕВХ, ЕАХ

; прерываем зависимость предотвращаем частичную задержку регистра

Обнуление регистра дважды может показаться излищним, но без MOV ЕАХ, О последние инструкции будут ждать, пока выполниться медленный DIV, а без XOR ЕАХ, ЕАХ случится частичная задержка регистра.

Инструкция FNSTSW АХ уникальна: в 32-битном режиме она ведет себя так же, ка* если бы писала в весь ЕАХ. Фактически она делает в 32-битном режиме следующее:

AND ЕАХ,OFFFFOOOOh / FNSTSW TEMP / OR EAX,TEMP Поэтому при чтении регистра после этой инструкции не возникнет частичное задержки регистра в 32-битном режиме.

FNSTSW АХ / MOV ЕВХ,ЕАХ MOV АХ,О / FNSTSW АХ

задержка только в 16-ти битном режиме задержка только в 32-х битном режиме

6.19.2. Частичные задержки флагов

Регистр флагов также может вызвать частичную задержку:

СМР ЕАХ, INC ЕСХ JBE XX

задержка



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 [ 63 ] 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88