информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
За кого нас держат?Где водятся OGRыСтрашный баг в Windows
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Про оптимизацию, АтлонХР и ассемблер. 05.06.03 16:07  Число просмотров: 1161
Автор: Yurii <Юрий> Статус: Elderman
<"чистая" ссылка>
> Тут полезнее оптимизировать процессор. Килобитные регистры
> использовать (сумматор, регистр сдвига, умножалку за один
> такт...) Скорость подскочет более, чем в 1024/32=32 раза. И
> не надо на 32 писюках запускать - что дороже 32 писишки или
> процессор, хоть он и более дорогой получиться.

Проект взлома RC5-72 рассчитан на энтузиастов,
суперкомпьютеров не имеющих.

> Ну на килобитный ключ немерено времени уйдет, стало быть
> алгоритм не оптимален, вот если бы 1024 итерации хоть и по
> секунде каждая...

Алгоритм оптимален (или близок к этому) в условиях данного
оборудования. Можно оптимизировать железо, но эта задача
других людей, да и другого уровня сложности.
<programming>
Про оптимизацию, АтлонХР и ассемблер. 05.06.03 13:35  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
Отредактировано 05.06.03 13:38  Количество правок: 1
<"чистая" ссылка>
Наткнулся тут на постинг, но он пропал куда-то, а тема интересная.
Вообще-то это надо в hacking, но hacking стал несколько cracking'ом (забыли про настоящий смысл хакинга).

> Если конкретно, то интересуют тайминги инструкций и
> спариваемость команд. Ну и примеры/текстовку на эту тему.

У меня было описание Техно-486, тайминги, оптимизация, такое понаписано было, что я бы ни за что сам не догадался.

> На amd.com я этого не нашел, хотя может быть просто слепой
> был.

Я на их сайте описание Хамера нашел в акробат-формате на 20 мегабайт. Почитал - интересно. Я это к тому, что екзотические полезные микрокоманды не все компиляторы поймут, это во-первых. А во-вторых в атлонах оптимизировать код бесполезно. Нет, можно, конечно до десятка тактов с сотни выжать. Но не ужели так кретично, чтобы программа считалась 9 часов вместо 10. А если время расчета и так мало (меньше секунды), то мучиться, чтобы на 10% его сократить тоже бессмысленно.
Как я уже когда-то писал, если потрудиться над алгоритмом, можно раз так в 10, 100 и даже в 1000 ускорить работу программы. Есть еще одно решение - не пожалеть $10-$30 при пукупке процессора, и эффект можно еще больше получить. А если денег жалко, можно частоту на те же 10% поднять (оверклокинг).
Ощутимого (более, чем на 1/3) прироста скорости ручной оптимизацией не достигнуть по сравнению с компилятором. Атлону побарабану какой код втягивать, он все-равно его в приблизительно один и тот-же микрокод перелопатит. И 9 (если не ошибаюсь) RISK процессоров загрузить по-полной тяжело, и переходы он хорошо угадывает.
Замерялку можно и самому написать. Не забыть только про условия (инструкция/данные находится/ненаходится в кеш-памяти, независимость от предыдущей инструкции). По моим замерам простейшие инструкции он со скоростью две с половиной за один такт делает. Видимо сколько из памяти/кеши-памяти закачать успевает.
Еще один момент - можно оптимизации у оптимизирующего компилятора поучиться. Ассемблерный код смотреть, который из-под него выползает. GCC рекомендую, про остальные не ручаюсь. На самом деле там, где человек чего-то ни учтет, компилятор не ошибется, если его (компилятор) только "научили" всему.
А такую документацию и я с удовольствием бы почитал.

> Спасибо.
Про оптимизацию, АтлонХР и ассемблер. 05.06.03 15:08  
Автор: Yurii <Юрий> Статус: Elderman
<"чистая" ссылка>
> Я это к тому, что екзотические полезные микрокоманды не все
> компиляторы поймут, это во-первых.

Что такое микрокоманды? Микрокод? Так к нему у нас доступа нет вроде...
Или ты про команды, специфичные для каждого процессора?

> А во-вторых в атлонах оптимизировать код бесполезно. Нет, можно,
> конечно до десятка тактов с сотни выжать. Но не ужели так кретично,
> чтобы программа считалась 9 часов вместо 10. А если время расчета
> и так мало (меньше секунды), то мучиться, чтобы на 10% его
> сократить тоже бессмысленно.

Это если пишешь задачу под себя или на один раз. Но, во-первых, бывает
спортивный интерес, и, во-вторых, если задача критична к скорости,
используется часто и многими людьми, то тут и пооптимизировать можно.

> Как я уже когда-то писал, если потрудиться над алгоритмом,
> можно раз так в 10, 100 и даже в 1000 ускорить работу программы.

Да, правильно. Но когда алгоритм уже оптимален, наступает очередь кода.
Пример рядом - взлом RC5.
Про оптимизацию, АтлонХР и ассемблер. 05.06.03 15:48  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
<"чистая" ссылка>
> Что такое микрокоманды? Микрокод? Так к нему у нас доступа
> нет вроде...
> Или ты про команды, специфичные для каждого процессора?

Ну да, MMX, 3Dnow+, SSE...

> Это если пишешь задачу под себя или на один раз. Но,
> во-первых, бывает
> спортивный интерес, и, во-вторых, если задача критична к
> скорости,
> используется часто и многими людьми, то тут и
> пооптимизировать можно.

Тут полезнее оптимизировать процессор. Килобитные регистры использовать (сумматор, регистр сдвига, умножалку за один такт...) Скорость подскочет более, чем в 1024/32=32 раза. И не надо на 32 писюках запускать - что дороже 32 писишки или процессор, хоть он и более дорогой получиться.

> Да, правильно. Но когда алгоритм уже оптимален, наступает
> очередь кода.
> Пример рядом - взлом RC5.

Ну на килобитный ключ немерено времени уйдет, стало быть алгоритм не оптимален, вот если бы 1024 итерации хоть и по секунде каждая...
Про оптимизацию, АтлонХР и ассемблер. 05.06.03 16:07  
Автор: Yurii <Юрий> Статус: Elderman
<"чистая" ссылка>
> Тут полезнее оптимизировать процессор. Килобитные регистры
> использовать (сумматор, регистр сдвига, умножалку за один
> такт...) Скорость подскочет более, чем в 1024/32=32 раза. И
> не надо на 32 писюках запускать - что дороже 32 писишки или
> процессор, хоть он и более дорогой получиться.

Проект взлома RC5-72 рассчитан на энтузиастов,
суперкомпьютеров не имеющих.

> Ну на килобитный ключ немерено времени уйдет, стало быть
> алгоритм не оптимален, вот если бы 1024 итерации хоть и по
> секунде каждая...

Алгоритм оптимален (или близок к этому) в условиях данного
оборудования. Можно оптимизировать железо, но эта задача
других людей, да и другого уровня сложности.
Про оптимизацию, АтлонХР и ассемблер. 06.06.03 10:16  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
<"чистая" ссылка>
> Алгоритм оптимален (или близок к этому) в условиях данного
> оборудования. Можно оптимизировать железо, но эта задача
> других людей, да и другого уровня сложности.
Ага, оптимальный, тысячи компьютеров в сети месяцами/годами ломают перебором ключа. Не похоже, чтобы каждый компьютер столько времени одну итерацию считал. Я имел в виду алгоритм сложности порядка N, где N длина ключа в битах, который пока не придуман. А то это похоже на пробивание крепостной стены лбом - когда-нибудь она все-таки рухнет.
Про оптимизацию, АтлонХР и ассемблер. 06.06.03 10:38  
Автор: Yurii <Юрий> Статус: Elderman
<"чистая" ссылка>
> Ага, оптимальный, тысячи компьютеров в сети месяцами/годами
> ломают перебором ключа. Не похоже, чтобы каждый компьютер
> столько времени одну итерацию считал.

В смысле "не похоже"? Тогда на что это похоже?
Распакуй клиента, дизассемблируй и посмотри.

> Я имел в виду алгоритм сложности порядка N,
> где N длина ключа в битах, который пока не придуман.

Да просто это задачи разной степени сложности.
Немного оптимизировать клиента я смогу,
а вот оптимизировать алгоритм пока не получаецца почему-то.

> А то это похоже на пробивание
> крепостной стены лбом - когда-нибудь она все-таки рухнет.

В разных ситуациях - разные решения.
Э-э-э-э 05.06.03 14:56  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
А тут отвечать надо?

В общем если я правильно понял пост, то например у Intel для каждого поколения процессоров есть "Intel Architecture Software Developer's Manual" (гуглом по названию можно найти их на сайте интела). Там и система команд и формат опкодов и псевдокод для команд, тайминга нет, но он не имеет смысла, так как очень многие факторы влияют на него, а писать для каждой команды все условия в которых она может исполняться с указанием времени исполнения в данных условиях - по моему нет смысла.

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

А дока по спариванию команд в том же "IA SoftDevel Manual; volume 3: System Programming" есть chapter 14: Code Optimization. В частности спариванию там отведен подраздел 14.5.1 "Instruction Pairing Guidelines", где описаны все правила, которыми руководствуется проц при спаривании команд (действительно все, потому как дока от разработчика)

ЗЫ: Про AthlonXP не знаю, но думаю оптимизацию все-таки стоит доверить компилятору. Потому как я например всю жизнь сижу на Celeron-ах и не думаю, что атлоновский код будет у меня сильно шустрым.
Э-э-э-э 05.06.03 16:19  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
Отредактировано 05.06.03 16:24  Количество правок: 2
<"чистая" ссылка>
> А тут отвечать надо?

Если есть, что ответить, то почему бы и нет.

У меня описание 486 было, там тайминги были указаны при различных условиях.
Особенно меня тронуло в ниже приведенном приложении, что "чистить" стэк добавлением к регистру-указателю вершины (3 байта команда) быстрее, чем POP (1 байт команда). POP с памятью работает (много тактов процессора жрет в зависимости от коэффициента умножения шины), а добавление в конвеере.
А еще - сложение трех чисел за ноль-один тактов на этапе дешифрации адреса.

> ЗЫ: Про AthlonXP не знаю, но думаю оптимизацию все-таки
> стоит доверить компилятору. Потому как я например всю жизнь
> сижу на Celeron-ах и не думаю, что атлоновский код будет у
> меня сильно шустрым.

Ну если команды mov, add, mul, cmp, inc... оба проца за такт делают, то разницы стало быть не будет.

===========================================================================
`д`мПриложение G. Оптимизация кода `*
---------------------------------------------------------------------------

Процессор i486 совместим по коду и по данным с процессорами 386(TM) DX и
SX. Были добавлены всего лишь три команды уровня прикладного
программирования, которые полезны в специальных ситуациях. Любая
существующая прикладная программа для процессора 8086/8088, 80286 и 386
может быть выполнена на процессоре i486 немедленно, без всякой
дополнительной модификации и перекомпиляции. Любой компилятор, который
генерирует код для процессоров семейства 386, будет также генерировать
код, который будет выполняться на процессоре i486 без какой-либо
модификации.
Тем не менее, сушествует несколько способов оптимизации кода, которые
сделают выполнение прикладных программ на процессоре i486 более быстрым,
при помощи всего лишь минимальных изменений или вообще безо всяких
изменений по отношению к их реализации для процессоров 386 DX или SX, за
исключением, быть может, различий в размере кода. Эти способы следует
применять по отношению к выбору последовательности команд и командам
управления для того, чтобы получить преимущества встроенного модуля режима
конвейерной обработки процессора i486 и большой кэш-памяти, расположенной
на одной микросхеме.


`к`дG.1 Режимы адресации `*

Подобно процессору 386, процессору i486 необходим дополнительный такт для
генерации исполнительных адресов, когда используется индексный регистр.
Более того, если используется одна индексная компонента (т.е. одновременно
не используются базовый регистр и индексный регистр), и нет необходимости
в масштабировании, более быстрым является использование регистра в
качестве базового, а не в качестве индексного. Например :

mov eax, [esi] ; использование esi в качестве базы
mov eax, [esi*] ; использование esi в качестве индекса, 1
; такт дополнительно

Если используются и база, и индекс, или используется масштабирование
индекса, более быстрым способом адресации является использование
комбинированного метода, даже если это и займет один дополнительный
тактовый цикл процессора при выполнении.
Когда регистр используется в качестве базовой компоненты, тогда
используется дополнительный тактовый цикл, если этот регистр являлся
приемником в команде, непосредственно выполнявшейся перед данной командой
(предполагается, что все операции уже находятса в предварительно созданной
очереди). Поэтому для получения наибольшего быстродействия две команды
должны разделяться по крайней мере еще одной командой. Например:

add esi, eax ; esi - регистр-приемник
mov eax, [esi] ; esi - базовый регистр, 1 такт дополнительно

Существуют также и другие неявные или косвенные методы использования
приемника и базового регистра, в первую очередь регистра указателя стека
ESP. Регистр ESP является неявной базой всех команд типа PUSH/POP/RET и он
же является неявным приемником в командах CALL/ENTER/LEAVE/RET/PUSH/POP.
Более того, команда LEAVE, следующаа непосредственно за командой RET,
будет использовать один дополнительный цикл. Но если команды LEAVE и RET
реорганизованы таким образом, что одну от другой отделяет какая-то другая
команда, не требуется никаких дополнительных тактов. (Смотри также другие
рекомендации, касающиеся команды LEAVE).
Нет никакой необходимости разделять последовательные команды PUSH/POP.
Процессор i486 допускает такую последовательность без использования
дополнительного такта.
Все такие преобразования последовательности команд не влияют на выполнение
программы на 386 процессоре.
Процессор i486 также требует дополнительного такта для выполнения команды,
которая имеет одновременно и операнд - непосредственное значение, и
операнд, заданный как смещение в памяти. Например :

mov указатель на двойное слово foo, 1234h ; одновременно и
непосредственное значение, и операнд - ; смещение в памяти.
mov указатель на двойное слово baz, 1234h
mov [ebp-200], 1234h

Когда требуется использовать константы, более эффективно использовать
непосредственные значения констант вместо предварительной загрузки
констант в регистры. Но если одна и та же константа используется больше,
чем один раз, то быстрее будет загрузить значение этой константы в регистр
и затем много раз использовать этот регистр. Эта оптимизация не влияет на
выполнение программы на 386 процессоре. Следующая последовательность
действий выполняется быстрее, чем приведенная выше, если все команды
находятся в предварительно созданной очереди, и, поскольку команды короче,
их в действительности легче организовать в очередь :


mov eax, 1234h
mov указатель на двойное слово foo, eax
mov указатель на двойное слово baz, eax
mov [ebp-200], eax


`к`дG.2 Модуль предварительной выборки `*

Модуль предварительной выборки процессора i486 получает доступ к
расположенной на микросхеме кэш-памяти для того, чтобы заполнить
предварительную очередь команд в тот момент, когда кэш-память не
задействована для работы и имеется достаточно места в очереди для
размещения другой строки кэша (16 байт). Если предварительная очередь
команд пуста, может потребоваться три дополнительных такта для запуска
новой команды. Предварительная очередь команд занимает 32 байта (2 строки
в кэш-памяти).
Так как доступ к данным всегда имеет высший приоритет по сравнению с
запросами на предварительную выборку, поддержание кэш-памяти в состоянии
занятости при помощи доступа к данным может заблокировать модуль
предварительной выборки.
Более того, важно организовать команды таким образом, чтобы не
использовалась постоянно шина памяти путем последовательности команд
обращения к памяти. Команды должны быть реорганизованы таким образом,
чтобы имелась команда, не обращающаяся к памяти (например, команда работы
регистр/регистр), по крайней мере за два такта до того, как предварительно
сформированная очередь команд станет исчерпаной. Например :


----------------------------------T----------------------------
¦ Команда ¦ Длина ¦
+---------------------------------+----------------------------+
¦ mov память, 1234567h ¦ 10 байт ¦
¦ mov память, 1234567h ¦ 10 байт ¦
¦ mov память, 1234567h ¦ 10 байт ¦
¦ mov память, 1234567h ¦ 10 байт ¦
¦ add регистр, регистр ¦ 2 байта ¦
L---------------------------------+-----------------------------

Если предварительно сформированная очередь команд полна на момент начала
работы, тогда после выполнения третьей команды MOV появляется достаточно
пространства для другой строки кэша в очереди, но, так как шина памяти
продолжает постоянно использоваться, нет необходимого времени для того,
чтобы передать строку из кэша в предварительно формируемую очередь команд.
Если перед или после третьей команды MOV не будет вставлена команда, не
обращающаяся к памяти, очередь будет исчерпана четвертой командой MOV. В
этом случае команды должны быть реорганизованы таким образом, чтобы
команда ADD была расположена до или после третьей команды MOV, для того,
чтобы разрешить кэш-памяти переслать очередную командную строку в модуль
предварительной выборки.
Ни одна из подобных реорганизаций команд не будет оказывать влияния на
скорость выполнения программы на процессоре 386 DX.


`к`дG.3 Выравнивание кэша и кода. `*

При работе на процессоре 386 приемник любой из команд JUMP/CALL/ RET
должен быть выровнен по адресу, кратному 4, это помогает модулю
предварительной выборки команд в формировании предварительной очереди
команд со всей допустимой быстротой, так как выборка выполняется по 4
байта за одно обращение при выровненных границах. Так как на процессоре
i486 имеется кэш-память на микросхеме, любая предварительная выборка
команд будет выбирать 16 байт для заполнения строки кэша. По этой причине
наилучшее быстродействие может быть достигнуто путем выравнивания
операндов-приемников в командах JUMP/CALL/RET по адресам, кратным 16.
Однако выравнивание по адресам, кратным 16, является причиной увеличения
размеров кода, и поэтому важен компромисс между скоростью выполнения и
размерами кода.
Более того, рекомендуется, чтобы только входные адреса функций (т.е.,
приемники команд CALL) были выровнены по адресам, кратным 16; в то время
как все метки (т.е. приемники в командах JUMP) продолжали бы оставаться
выровненными по адресам, кратным 4.
На процессоре i486 требуется дополнительно до пяти тактов для начала
выполнения команды, если она разбивается более чем на две 16-байтные
строки кэша. Например, если команда CALL заканчивается на адресе
0x0000000Е и следом за ней идет команда умножения байтов, тогда по
возвращении из выполнения команды CALL процессор должен использовать
дополнительно пять тактов для того, чтобы заполнить предварительно
формируемую очередь команд, если только целевая команда уже не находится в
кэше. Даже если целевая команда уже находится в кэше, тем не менее
потребуется дополнительные 2 цикла для того, чтобы переслать ее в модуль
предварительной выборки команд.


Поэтому, если компилятору известно выравнивание приемника, тогда будет
быстрее включить команды заполнения так, чтобы команда умножения байтов
начиналась с выровненного адреса. Это может быть достигнуто либо путем
перестановки последовательности команд, либо включением команды NOP.
Такое выравнивание команд будет также влиять на скорость выполнения на
процессоре 386.


`к`дG.4. Команда NOP `*

Иногда программам необходим заполнитель между командами для того, чтобы
выравнивать их. На процессорах 386 и i486 таковым заполнителем является
однобайтовая команда NOP, которая в действительности обменивает содержимое
регистра ЕАХ с содержимым регистра ЕАХ же.
Команды других длин могут быть выполнены за один цикл. Таблица ниже
приводит некоторые из них.

1-байная inc регистр ; модифицирует регистр и
; флаги
2-байтная mov регистр, регистр ; в действительности NOP
3-байтная lea регистр, 0[регистр] ; в действительности NOP,
; с использованием
; 8-разрядного смещения
5-байтная mov eax, 0 ; модифицирует регистр eax
5-байтная add eax, 0 ; модифицирует флаги
6-байтная lea reg, 0[eax] ; в действительности NOP,
; с использованием
; 32-разрядного смещения

Вдобавок, многие команды процессоров 386/i486 имеют особые формы и длины,
использующие непосредственные данные различной длины или смещения в памяти
различной размерности. Также некоторые команды имеют укороченные формы,
если операндом-приемником является регистр EAX/AX/AL.
Не все команды с различными формами будут выполняться за одно и тоже
время. Примером, в котором различные формы будут выполняться за различное
время, являются команды PUSH/POP/REG. Если они закодированы в однобайтовую
форму, они будут выполняться за один цикл, но если они закодированы в
2-байтную форму, они будут выполняться за 4 цикла.
Команды заполнения NOP будут также выполняться быстрее, чем команда XCHG
на процессорах семейства 386. Использование различных форм одной и той же
команды не влияет на быстродействие при выполнение на процессоре 386.


`к`дG.5. Команды работы с целыми числами`*

Процессор i486 может выполнять большинство часто используемых команд
(таких, как загрузка или запоминание регистра, АЛУ-операции с регистром, и
т.д.) за один такт. Однако, в отличие от процессора 386, некоторые из
операций с памятью занимают теперь больше циклов, чем соответствующие
операции с регистрами. Например, команда PUSH MEM :

---------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+--------------------+----------------------+--------------------+
¦ mov регистр,память ¦ 4 ¦ 1 ¦
¦ push регистр ¦ 2 ¦ 1 ¦
¦ push память ¦ 5 ¦ 4 ¦
L--------------------+----------------------+---------------------

Tаким образом, для процессора i486, загрузка значения из памяти в регистр
и затем занесение этого регистра в стек приведет к чистому сохранению 2
тактов; но для процессора 386 DX таже самая последовательность команд
приведет к чистой потере одного такта. Однако для того, чтобы загрузить
значение в регистр на процессоре i486, необходимо найти пустой регистр;
если действие по загрузке значения уничтожит значение регистра, которое
могло быть использовано позднее, то сохранение значения может привести к
отрицательному результату по причине потери повторно используемого
значения регистра.

Другим примером служит команда LEAVE :

-------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+------------------+----------------------+--------------------+
¦ mov esp, ebp ¦ 2 ¦ 1 ¦
¦ pop ebp ¦ 4 ¦ 1+1 (штраф за esp) ¦
¦ leave ¦ 4 ¦ 5 ¦
L------------------+----------------------+---------------------


Опять же, для процессора i486, выполнение последовательности команд
MOV/POP приводит к чистому сохранению 2 тактов по сравнению с командой
LEAVE; в то время, как выполняясь на процессоре 386 DX, команда LEAVE
одновременно и быстрее, и короче. Однако, так как первая команда MOV
использует регистр ESP в качестве приемника и команда POP также неявно
использует регистр ESP в качестве базы (как уже упоминалось выше), эта
последовательность действий приводит к получению одного штрафного такта,
если только две команды не разделены другой командой. Если возможно таким
образом переупорядочить команды, чтобы команды MOV/POP были бы разделены
полезной командой, тогда чистый выигрыш в тактах по сравнению с командой
LEAVE составил бы 3 такта на процессоре i486.
Так как процессор i486 может работать с операндами в регистрах быстрее,
чем с операндами в памяти (как и почти большинство других архитектур),
важно иметь хорошее размещение регистров и оптимизацию трекинга значений в
любом из компиляторов. С другой стороны, нет сохранения при загрузке
каждого значения перед его использованием, как это сделано в RISC
архитектуре. Процессор i486 может выполнять команды АЛУ типа
регистр,память также быстро, как и последовательности команд
загрузить/операция/запомнить. Например, для присваивания : память1 =
память1 + память2 - можно использовать следующие последовательности
команд, с варьированием общего количества тактов для процессоров 386 DX и
SX, но одним и тем же количеством тактов для процессора i486 :

-------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+------------------+----------------------+--------------------+
¦ mov eax, память1 ¦ 4 ¦ 1 ¦
¦ mov ebx, память2 ¦ 4 ¦ 1 ¦
¦ add eax, ebx ¦ 2 ¦ 1 ¦
¦ mov память1, eax ¦ 2 ¦ 1 ¦
¦ ¦ ¦ ¦
¦ mov eax, память1 ¦ 4 ¦ 1 ¦
¦ add eax, память2 ¦ 6 ¦ 2 ¦
¦ mov память1, eax ¦ 2 ¦ 1 ¦
¦ ¦ ¦ ¦
¦ mov eax, память1 ¦ 4 ¦ 1 ¦
¦ add память2, eax ¦ 7 ¦ 3 ¦
L------------------+----------------------+---------------------

Команда MOVZX является другим примером, в котором процессор i486 может
работать быстрее с использованием простых команд, если приемником является
регистр, который в свою очередь может быть адресуем побайтно. Например,
загрузка значения байта :

---------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+--------------------+----------------------+--------------------+
¦ movzx eax, память1 ¦ 6 ¦ 3+1 (префикс 0Fh) ¦
¦ xor eax, eax ¦ 2 ¦ 1 ¦
¦ movb al, память1 ¦ 4 ¦ 1 ¦
L--------------------+----------------------+---------------------

Таким образом, для процессора i486, сначала очистка регистра и затем
загрузка значения регистра может дать в качестве результата чистую
экономию двух тактов (в зависимости от того, где такт декодирования
префикса может быть перекрыт предыдущей командой, смотри Раздел G.8,
посвященный Префиксным кодам операций), в то время как нет разницы в
выполнении команд на процессоре 386 DX.


`к`дG.6. Коды условия `*

В некоторых языках программирования высокого уровня иногда необходимо
преобразовать результат булевского условия (а именно, равенства,
больше-чем или меньше-чем и так далее) в значение истина или ложь (т.е.
0/1). Процессоры 386 и i486 обычно поддерживают результаты сравнения в
регистре флагов, поэтому для того, чтобы преобразовать результат сравнения
в значение истина/ ложь, необходимо преобразовать значения флагов в целые
значения.
Процессоры 386 и i486 имеют множество команд SETcc, которые выполняют
такое преобразование, однако команды SETcc занимают 3 или 4 такта при
выполнении на процессоре i486, в зависимости от того, когда условие
проверяется на истину или ложность. Специально при сравнении значений без
знака на больше чем или меньше чем, имеется необязательная для
использования последовательность действий. Например, если "x" и "y"
являются значениями без знака, и "x" загружен в регистр eax и "y" загружен
в регистр ecx, тогда код для сравнения "(x<y)" может быть получен
следующими способами :


-------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+------------------+----------------------+--------------------+
¦ cmp eax, ecx ¦ 2 ¦ 1 ¦
¦ mov eax, 0 ¦ 2 ¦ 1 ¦
¦ jnb L1 ¦ 7 + m/3 ¦ 3/1 ¦
¦ mov eax, 1 ¦ 2 ¦ 1 ¦
¦ L1: ¦ ¦ ¦
¦ cmp eax, ecx ¦ 2 ¦ 1 ¦
¦ setb al ¦ 4/5 ¦ 4/3 ¦
¦ movsx eax, al ¦ 3 ¦ 3 ¦
¦ cmp eax, ecx ¦ 2 ¦ 1 ¦
¦ sbb eax, eax ¦ 2 ¦ 1 ¦
¦ neg eax ¦ 4 ¦ 1 ¦
L------------------+----------------------+---------------------

Таким образом, использование команды SBB для получения установленных
значений флагов при сравнении без знака дает наивысшее быстродействие, без
прерывания предварительно выбранного конвейерного процесса, так как не
используется никаких передач управления. Обратите внимание, что хотя это и
специфический процесс для проверки условия "(x<y)", представляется
возможным преобразовать другие проверки к данной форме посредством либо
отрицания условия, либо заменой операндов местами.
Такие замены команд кода условия также оказывают влияние на выполнение
программ на процессоре 386.


`к`дG.7. Команды работы со строками `*

Так же, как и процессор 386 DX, процессор i486 выполняет команды работы со
строками медленнее, чем команды загрузки и сохранения. Например, команда
LODS :

-------------------T----------------------T--------------------
¦ Команда ¦ Такты ЦПУ 386(ТМ) DX ¦ Такты ЦПУ i486(TM) ¦
+------------------+----------------------+--------------------+
¦ mov eax, [esi] ¦ 4 ¦ 1 ¦
¦ add esi, 4 ¦ 2 ¦ 1 ¦
¦ ¦ ¦ ¦
¦ lods ¦ 5 ¦ 4 ¦
L------------------+----------------------+---------------------

Команда LODS выполняет больше действий, чем отдельная команда MOV, она
также обновляет регистр ESI. Однако, если нет необходимости в обновлении
регистра, то команда MOV приводит к чистому сохранению 3 тактов и на
процессоре 386 DX, и на процессоре i486. Печальным компромиссом служит то,
что команда LODS короче команды MOV.
Также и при не повторяющемся использовании отдельные команды MOV всегда
будут выполняться быстрее, чем строчная команда MOVS. И даже в цикле RET,
если цикл достаточно короткий, быстрее использовать отдельные команды
загрузки и сохранения, чем устанавливать значения для REP'MOVS.
Компромисом вновь является противостояние скорости выполнения и размеров
кода, при использовании команды REP'MOVS цикл будет короче, но медленнее.
Однако, как указывалось выше, длинная последовательность команд загрузки и
сохранения может закрыть доступ модулю предварительной выборки к
предварительному формированию очереди команд и таким образом затормозить
процессор, поэтому не рекомендуется перемещать более 16 байт командами
загрузки и сохранения без использования между ними команд, не работающих с
памятью, чтобы позволить устройствы предварительной выборки обратиться к
кэш-памяти.
Аналогичные оптимизации могут быть проведены для команды STOS и других
команд работы со строками. Такие замены команд работы со строками влияют
на выполнение программы на 386 процессоре.


`к`дG.8. Команды работы с числами с плавающей точкой`*

Так же, как и комбинация процессора 386 с математическим сопроцессором
387, модуль обработки операций плавающей точкой процессора i486 является
отдельным вычислительным устройством и работает параллельно с
целочисленным модулем, даже если физически они и размещаются на одной
микросхеме. Следовательно, любая последовательность команд, которая
допускает параллельное использование этих двух независимых модулей, будет
работать быстрее.
Команды работы с числами с плавающей точкой не следует размещать одну
вслед за другой. Эти команды следует упорядочить таким образом, чтобы две
команды вычислений с плавающей запятой разделялись другой, не связанной с
числами с плавающей точкой, командой, чтобы два модуля могли работать
параллельно. Обратите особое внимание на продолжительность в тактах
процессора для команд работы с числами с плавающей точкой, для того, чтобы
подходящее количество целочисленных команд могло быть выполнено без того,
чтобы поставить модуль обработки операций с плавающей точкой в состояние
ожидания момента, когда может быть выполнена следующая команда вычислений


с плавающей точкой. Такое изменение порядка команд также влияет на
скорость работы в комбинации процессор 386/математический сопроцессор 387,
однако количество тактов, используемое процессором, намного меньше, чем
количество тактов, используемое математическим сопроцессором 387 для
выполнения одних и тех же действий над числами с плавающей точкой.
Как напоминание, запомните, что любое простое перемещение или упорядочение
чисел с плавающей точкой должно выполняться не при помощи модуля обработки
операций с плавающей запятой, а при помощи целочисленного модуля с
целочисленными же командами. Также команда FWAIT никогда не требуется для
выполнения простейших вычислений с плавающей точкой.


`к`дG.9. Префиксные коды операций `*

На любом ис процессоров все префиксные коды операций, включая 0Fh,
перекрытие сегмента, размерность/адресация операнда, блокировка шин,
повторы и так далее требует дополнительных тактов процессора для
декодирования. Эти такты могут быть перекрыты за счет выполнения
предыдущих команд, если они требуют более одного такта для своего
выполнения.
Более того, быстрее будет преобразовать 16-разрядный операнд в
32-разрядный и затем работать с 32-разрядным значением, вместо того, чтобы
использовать префикс 66h для работы с 16-разрядным операндом.
Если используется префиксный код операции, попытайтесь переупорядочить
команды таким образом, чтобы команда с префиксом стояла следом за
командой, которой для выполнения требуется несколько тактов.
Дополнительной причиной неиспользования 16-разрядных операндов является
то, что если приемником команды является 16-разрядный регистр и
непосредственно следующая за ней команда использует этот регистр в
качестве 32-разрядного операнда, то будет налагаться один штрафной такт.
Как и ранее, эти две команды должны быть отделены друг от друга какой-либо
иной командой для того, чтобы избежать штрафа.


`к`дG.10. Перекрывающиеся такты`*

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

В частности, перекрываются следующие комбинации :

- Наличие индексного регистра и непосредственного значения вместе со
смещением в памяти будет стоить всего один штрафной такт процессора.
- Наличие префиксного кода операции и использование регистра результата
предыдущей операции в качестве базового регистра будет стоить всего один
штрафной такт процессора.
- Наличие префиксного кода операции следом за командой, требующей для
выполнения несколько тактов процессора, не налагает никаких дополнительных
штрафных тактов процессора.


`к`дG.11 Руководство по использованию остальных команд`*

Множество команд процессоров 386 создавалось исходя из некоторого опыта
практического программирования. Множество этих практических наблюдений
оказалось полезным для программирования на языке ассемблера процессора
i486, и может оказаться само по себе интересным при создании компиляторов.

- Используйте регистр EAX где только возможно. Многие команды становятся
на один байт короче при использовании регистра EAX, такие, как загрузка в
память и сохранение из памяти при использовании абсолютных адресов,
пересылка значений в другие регистры при помощи команды XCHG, и команды,
которые используют непосредственные значения в качестве операндов.
- Используйте по возможности сегмент D-данных. Команды, работающие с
D-пространством, на один байт короче команд, которые используют другие
сегменты данных по причине отсутствия префикса перекрытия сегмента.
- Придавайте особое значение коротким одно-, двух- и трехбайтным командам.
Так как команды процессора i486 начинаются и заканчиваются на границах
байтов, возможно будет обеспечить такое кодирование команд, которое будет
более компактным по отношению к кодированию для процессоров, использующих
множество команд, выровненных по границам слов. Команда во множестве
команд с выравниванием по словам должна иметь длину в два или четыре байта
(или более). Побайтное выравнивание сокращает размерность кода и
увеличивает скорость выполнения команд.
- Получайте доступ к 16-разрядным данным при помощи команд MOVSX и MOVZX.
Эти команды используют расширение по знаку и расширение по нулю операндов
длиной в слово до длины в двойное слово. Это сокращает необходимость в
использовании дополнительных команд для инициализации старшего слова.
- Для скорейшего отклика на прерывание используйте при возможности
прерывание MNI.


- Вместо использования команды ENTER на лексическом уровне 0, используйте
фрагмент кода, аналогичный следующему :

PUSH EBP
MOV EBP, ESP
SUB ESP, BYTE_COUNT
Этот фрагмент выполняется за семь тактов, а не за десять.

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

- Команды перехода используются в двух основных формах : одна из форм
имеет непосредственное восьмибитовое значение для выполнения
относительного перехода в диапазоне от 128 байт назад до 127 байт вперед,
другой формой является полное 32-разрядное смещение. Многие программисты
на ассемблере используют длинную форму в ситуациях, когда может быть
использована короткая форма. Когда совершенно ясно, что может быть
использована короткая форма, явно укажите, что операнд-приемник имеет
размерность в один байт. Это подскажет ассемблеру, что надо использовать
короткую форму. Если ассемблер не поддерживает эту функцию, он выдаст
ошибку. Обратите внимание на то, что некоторые ассемблеры выполняют такую
оптимизацию автоматически.
- Используйте регистр ESP для ссылок на стек на самом глубоком уровне
вложенности подпрограмм. Не беспокойтесь относительно задания значения
регистра EBP и стека данных.
- Для быстрейшего переключения задач используйте программное переключение
задач. Это позволяет запоминать и восстанавливать меньшие по объему данные
о состоянии процессора. Смотри Главу 7 для обсуждения вопросов
многозадачности.
- Используйте команду LEA для сложения регистров. Когда в команде LEA
используются базовый регистр и индексный регистр, в операнд-приемник
загружается их сумма. Содержимое индексного регистра может быть
масштабировано кратно 2, 4 или 8.
- Используйте команду LEA для прибавления константы к регистру. Когда в
команде LEA используются базовый регистр и смещение, сумма загружается в
приемник. Команда LEA может быть использована вместе с базовым регистром,
индексным регистром, фактором масштабирования и смещением.
- Используйте команды перемещения целых для передачи данных формата с
плавающей точкой.
- Используйте форму команды RET с непосредственным значением дла счетчика
байт, а не команду ADD ESP. Это сохраняет при выполнении один тактовый
цикл и три байта на каждый вызов подпрограммы.
- Когда выполняется несколько обращений к переменной, адресуемой со
смещением, загрузите смещение в регистр.
- Команды PUSH и POP, когда используюся вместе с операндом в памяти,
используют на два больше тактов процессора, чем эквивалентная
двухкомандная последовательность, которая передает операнды через регистры
общего назначения перед занесением их в стек и восстановлением из стека.
- Команда LOOP использует при выполнении на два тактовых цикла больше, чем
эквивалентное уменьшение счетчика и команда условного перехода.
- Команда JECXZ использует при выполнении на один тактовый цикл больше,
чем эквивалентное сравнение и команда условного перехода.
Я не совсем это имел в виду 05.06.03 17:07  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Если есть, что ответить, то почему бы и нет.

> У меня описание 486 было, там тайминги были указаны при
> различных условиях.
Если оставаться в рамках совместимости с i486, то конечно время указать можно. На z80, например, самой быстрой командой обращения к памяти были push/pop и я лично перемещао указатель стека в видеопамять и рисовал там push-ами.

Но вот в современных условиях:

во-первых одна и та же система команд может использоваться в процессорах совершенно разных архитектур (яркий пример: amd и intel, чуть менее яркий - поколения процессоров самих этих производителей)

Соответсвенно во-вторых: меняются стратегии кеширования и распараллеливания. И в большинстве современных процессоров команды регистр-регистр и регистр-память чаще всего выполняются меньше одного такта. Тут многое зависит от заполненности кеша, выравнивания, пары этой команды и т.д.

В-третьих: использование разных расширений системы команд. Имеется в виду разных для разных производителей.

Ну и т.д.
Все-равно смысл такой оптимизации теряется. 06.06.03 10:48  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
Отредактировано 06.06.03 10:50  Количество правок: 1
<"чистая" ссылка>
Четверочную документацию я привел как пример, что что-то найти можно, и такты там могут быть.

> во-первых одна и та же система команд может использоваться
> в процессорах совершенно разных архитектур (яркий пример:
...
> Соответсвенно во-вторых: меняются стратегии кеширования и
> распараллеливания. И в большинстве современных процессоров
> команды регистр-регистр и регистр-память чаще всего
> выполняются меньше одного такта. Тут многое зависит от
> заполненности кеша, выравнивания, пары этой команды и т.д.

Ну если даже будет это описание и клоки на команду (зависимость операндов, наличие в конвеере/памяти, данные в регистре/памяти/кеши-1/кеши-2..., выравнивание кеша...)
Допустим оптимизируем маленикий фрагмент 11-17 инструкций может получиться десятки различных сочетаний, количество сочетаний умножим на количество условий, считаем такты, выбираем наилучший выриант.
Варианты будут отличаться на несколько тактов, при обшем их количестве на десятичный порядок превышающий разброс. А сколько времени уйдет на оптимизацию. И стоит ли этот прирост скорости потраченого времени на эту оптимизацию.
Попробуйте кто-нибудь - придумайте вычислительную задачку, реализуйте сначала на "С", потом оптимизируйте ее ассемблером и сравните время расчета.
Только надо быть осторожным, а то после компиляции со включеной опцией оптимизации компилятора прграмма считалась за нулевое время, и что самое интересное ответ был верен.
Гы. Я как раз о том же 06.06.03 10:56  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
Интел привел свои пути оптимизации скорее для разработчиков копмиляторов, нежели для простых смертных программеров.

> Попробуйте кто-нибудь - придумайте вычислительную задачку,
> реализуйте сначала на "С", потом оптимизируйте ее
> ассемблером и сравните время расчета.
Ага. Делал уже :-)
В небольших программках - или одинаково или ручная оптимизация иногда лучше. А вот большие проги на асме - и работать-то заставить та еще проблема. А еще с оптимизацией мудрить. Тут компилер по любому рулит :-)
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach