Блог → Сравниваем процессоры AMD и Intel - кто кого? Часть 2

Статья о сравнении процессоров AMD и Intel была бы неполной, если бы я не коснулся особенностей декодирования команд. Формирование набора команд архитектуры x86 происходило в те далёкие годы, когда оперативная память была на вес золота, и компактность кода доминировала над производительностью. Следуя принципу Клода Шеннона, который гласит что "более употребляемые команды должны кодироваться как можно более короткими последовательностями", и наоборот, инженеры Intel оптимизировали "язык" процессора под размер исполняемых программ, чем в итоге, серьёзно озадачили своих потомков. Переменная длина машинных команд оказалась препятствием на пути их параллельного исполнения, поскольку невозможно определить начало следующей команды, не декодировав предыдущую. Причем декодирование - это весьма сложный ресурсоёмкий процесс, требующий множества вычислений. По сути, это проблема большинства современных процессоров.

В Pentium III имеется три декодера. Однако, только первый из них может декодировать любую команду, а два остальные декодируют лишь команды, транслирующиеся в одну микрооперацию. У AMD Krypton-7 декодеров столько же (плюс еще один вспомогательный декодер для разбора сложных команд), зато все они равноправны - каждый из них может декодировать любую инструкцию за один такт. В результате - эффективность декодера Krypton-7 ощутимо выше Pentium III при выполнении неоптимизированных программ. Но дело в том, что подавляющее большинство компиляторов генерируют оптимизированный код, который равномерно "нагружает" все три декодера Pentium III так, что ни один из них не простаивает. Поэтому на типовых приложениях "продвинутость" декодеров Krypton-7 практически никакого прироста производительности не даёт.

И Pentium III, и Pentium II транслируют все х86-инструкции в микрооперации, передавая их на выполнение RISC-ядру (микрооперации часто называют ROP - RISC OPerations). Процессор Pentium III имеет два модуля целочисленной арифметики, два совмещенных модуля вычислений с плавающей точкой, и три модуля адресной арифметики. Это позволяет выполнять за один такт несколько микроопераций, обрабатываемых соответствующими устройствами.

Процессор Krypton-7 имеет девять модулей: три целочисленных модуля, три модуля вычисления адреса и три модуля вычислений с плавающей запятой. И все они могут работать параллельно! Пиковая производительность Krypton-7 достигает трех команд за такт, против двух у Pentium III. Но разница в их производительности вовсе не 3:2! В большинстве случаев команды либо требуют дополнительных тактов для загрузки из медленной оперативной памяти, либо производят сложные вычисления, чем сводят всю "прибыль" от параллелизма на нет. Еще хуже - если команды содержат неразрешимую зависимость по данным; тогда невозможно начать выполнение следующей команды, пока предыдущая не завершится.

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

Микропроцессоры Pentium строят свой анализ на основе двух последних событий, а Pentium MMX - четырех. Специальный буфер сохраняет информацию о 256 и 512 последних выполненных инструкциях переходов (не самих переходах!) для Pentium и Pentium II+ соответственно. Вероятность правильного прогноза составляет порядка 80% для Pentium и порядка 90% для Pentium II+. Неплохо, очень неплохо; но Krypton-7 показывает еще лучший результат: за счёт четырехкратно превосходящего буфера истории переходов коэффициент верных предсказаний поднимается до 95%. Любопытно, что у Krypton-7 размер буфера в четыре раза меньше, чем у Krypton-6, но коэффициент верных предсказаний остался таким же!

Если условный переход предсказан правильно, он выполняется за один такт, в противном случае ("промах") на него расходуется от четырёх до пяти (а иногда и больше) тактов. Таким образом, улучшенное предсказание переходов в Krypton-7 обеспечивает четырехпроцентный прирост производительности по сравнению с Pentium III. Разумеется, всё это справедливо лишь при том условии, что выполняемая программа не была специальным образом оптимизирована, иначе же разница в производительности окажется равной нулю, или очень близкой к нему.

И Krypton-б, и Krypton-7, и Pentium II+ используют стек возврата для ускорения выполнения инструкции RET (команда выхода из подпрограммы). Алгоритм предсказания следующий: при первом вызове CALL процессор запоминает адрес следующей за ней инструкции, и встретив команду RET, молниеносно переходит к нему, не дожидаясь пока эти данные будут считаны из кэша или оперативной памяти.

Pentium II+ способен запомнить до 12 вложенных вызовов, тогда как Krypton-6 - целых 16. И опять же, есть одно "но"! у Krypton-7 эта величина уменьшена - до такой же, как у Pentium II+. Любопытно, что авторы многих статьей утверждают: якобы Pentium II+ способен запомнить не более 4 вложенных вызовов. Это гнусная клевета! Никакие упреки в "недокументированности" не принимаются, ведь всё прекрасно описано даже в русскоязычном интерактивном учебнике по оптимизации от Intel. Таким образом, Krypton-7 по сравнению с Krypton-6 сделал шаг назад. Легко догадаться, чем вызван этот шаг - проектировщики Krypton-6 со всеми величинами явно переборщили. Ни история переходов, ни стек возврата не использовались на всю мощь - пустой расход транзисторов и потребляемой энергии. Процессор Krypton-7 так же хорошо предсказывает переходы, как и Krypton-6 - несмотря на то, что содержит вчетверо уменьшенный буфер и в полтора раза меньший стек.

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

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

В ранних процессорах Pentium конвейер целочисленных операций включал в себя пять стадий: Предвыборка -> Декодирование -> Вычисление эффективного адреса -> Исполнение -> Запись результата. В старших моделях процессоров Pentium конвейер значительно усложнился: выполнение команды занимает от одиннадцати до четырнадцати этапов: Динамический предсказатель переходов -> Статический предсказатель переходов -> Блок предвыборки инструкций -> Блок выборки -> Блок предекодирования -> Двухступенчатый декодер -> Блок переименования регистров -> Блок переупорядоченного чтения -> Блок резервирования -> Блок вычислительного ядра -> Блок переупорядоченной записи -> Блок регистров. Приблизительно по такой же схеме построен и конвейер Krypton-7. Однако за счёт объединения и упрощения декодера и блока выборки, он укладывает выполнение любой команды всего в десять стадий. Несмотря на то, что конвейер Krypton-7 короче, чем у старших моделей Pentium, фирма AMD характеризует свой процессор как суперконвейерный. Разница в длинах конвейеров между Krypton-7 и Pentium практически не сказывается на производительности, но более длинный и состоящий из максимально простых функциональных устройств конвейер Pentium II+ упрощает наращивание тактовой частоты, a вот Krypton-7 может в скором будущем встретиться с проблемами.

Сказанное выше относилось исключительно к целочисленным вычислениям. Операции с плавающей запятой в процессорах Pentium обрабатывались отдельным трехстадийным конвейером, отходящим от блока исполнения основного конвейера, в то время как процессоры AMD (до выхода Krypton-6 включительно) не умели конвейеризовать операции с плавающей запятой, отчего и проигрывали в производительности. Разработчики Krypton-7 наконец-то устранили этот недостаток, и теперь их процессор может одновременно выполнять целочисленные инструкции и инструкции с плавающей запятой. Однако, ввиду архитектуры своего конвейера, Krypton-7 тратит на сложение на один такт больше, чем Pentium II+, зато операцию умножения выполняет на один такт быстрее! А операции деления и извлечения квадратного корня Krypton-7 выполняет соответственно в полтора и два раза быстрее, чем Pentium II+! Таким образом, на наукоемких задачах, требующих интенсивных вычислений с плавающей запятой, Krypton-7 значительно превосходит Pentium III той же тактовой частоты (но не Pentium III Coppermine, с его интегрированным кэшем второго уровня, работающим на частоте ядра!).

Отдельно следует сказать о конвейеризации инструкций 3Dnow! и SSE. Процессоры Pentium II+ имеют только один конвейер для выполнения SIMD-инструкций, против двух у Krypton-7. Однако Pentium II+ обрабатывает большинство SIMD-инструкций за два такта, a Krypton-7 - за четыре. Уже за счет этого производительность Pentium III не хуже, чем у Krypton-7.

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

1: add еах, ebx
2: sub esi, еах
3: add есх, ebx
4: sub edi, есх


Команды 1 и 2 не могут выполняться одновременно, т.к. вторая использует результат вычислений первой. Но ничто не препятствует спариванию команд 1+3 и 2+4 - это позволит выполнить приведенный фрагмент за два тика вместо четырёх!

Подобное внеочередное выполнение команд обеспечивается планировщиком. Планировщик процессоров Pentium II+ и Krypton-7 работает не с машинными инструкциями, а с микрооперациями. Емкость планировщика, т.е. количество микроопераций, которое он может вместить в свой буфер, ограничивает глубину внеочередного выполнения. Упрощенно говоря, планировщик накапливает микрооперации, затем анализирует зависимости между ними и передает подходящие "спарки" вычислительным устройствам.

Целочисленный планировщик Pentium II+ видимо вмещает в себя до девятнадцати микроопераций (документация Intel по этому вопросу запутана и противоречива), у Krypton-7 - те же девятнадцать, что, правда, несколько меньше, чем у его предшественника Krypton-6 (у того размер буфера составлял 24 микрооперации). Впрочем, это практически не влияет на производительность, так как такого размера буфера вполне достаточно для устранения большинства зависимостей. Аналогичный планировщик существует и для операций с плавающей запятой. У Krypton-7 его емкость составляет 36 микроопераций, a вот Intel по этому вопросу хранит молчание.

С точки зрения программиста процессор Pentium III отличается от своего предшественника Pentium II более богатым набором SIMD-команд. Что это за команды? В 1966 году М. Флином была предложена, по-видимому, самая ранняя классификация процессорных архитектур. Принадлежность к тому или иному классу определялась параллелизмом обработки потока данных. Флинн рассмотрел четыре возможные комбинации:
а) одна команда одновременно обрабатывает одну порцию данных;
б) одна команда одновременно обрабатывает две и более порций данных;
в) две и более команд одновременно обрабатывают одну порцию данных;
г) несколько команд одновременно обрабатывают множество данных (последние два пункта имеют смысл только для многопроцессорных машин, и поэтому далее не рассматриваются).

Or английских выражений Single Instruction, Single Data (одна инструкция, одно данное) и Single Instruction, Multiple Data (одна инструкция, множественные данные) возникли аббревиатуры SISD и SIMD соответственно.

В микропроцессорах Intel 80x86 до недавнего времени присутствовали только SISD-команды - за исключением строковых инструкций, предваренных префиксом REP. которые с некоторой натяжной можно было рассматривать как SIMD-команды. Но первая полноценная SIMD-поддержка появилась лишь в Pentium MMX. Технология MMX позволяла одновременно обработать либо 8 байт, либо 4 слова, либо 2 двойных слова, но поддерживала операции только с целыми числами, что сильно ограничивало область ее применения. Этим обстоятельством воспользовалась компания AMD, добавившая в свой процессор набор SIMD-инструкций, манипулирующих с вещественными числами - 3Dnow!

Фирма Intel, очевидно, не желая отставать от конкурентов, добавила поддержку вычислений с плавающей точкой и приближенных табличных вычислений в свой новый процессор Pentium III, попутно вдвое увеличив разрядность регистров - с 64 бит до 128 и добившись возможности одновременного выполнения ММХ команд с инструкциями сопроцессора. Первоначально набор новых команд носил название MMX II, затем его попытались представить как нечто принципиально новое, перекрестив в KNI (Katamai New Instructions - "Katamai" - кодовое имя Pentium III). Переименование Katamai в Pentium III обессмыслило аббревиатуру KNI, и её место заняла другая аббревиатура - SIMD, а сам набор новых инструкций обозначился как SSE (Streaming SIMD Extensions).

На самом же деле, никаких революционных изменений в Pentium III не произошло, и удобство использования векторных команд по-прежнему оставляет желать лучшего. Вероятно, пройдет немало времени, пока, наконец, SIMD-инструкции серьёзно потеснят своих SISD "собратьев". Поддержка Pentium III уже включена в DirectX, однако, последний не покрывает всей сферы областей применения новых инструкций - это и обработка сигналов, и сортировка больших объемов данных, и распознавание образов, и многое-многое другое.

Фирма AMD также расширила набор SIMD-команд процессора Krypton-7. Но при этом он значительно скромнее, чем у Intel - 70 новых инструкций Pentium III, против 24 у Krypton-7. По своей эффективности 3Dnow! сильно уступает SSE, тем более, что новые команды Krypton-7 пока не поддерживаются DirectX, и поэтому говорить об их практическом использовании пока преждевременно. Разумеется, Microsoft рано или поздно включит их поддержку в очередной DirectX, но польза от этого будет сомнительна. За счет большей по сравнению с Pentium III площади кристалла, себестоимость Krypton-7 окажется ощутимо выше, чем у его конкурента, и, если только AMD не начнет продавать его себе в убыток, захватить игровой рынок она вряд ли сможет. А вот серверам (наиболее вероятная сфера применения Krypton-7) "мультимедийные" команды абсолютно ни к чему. Впрочем, все будет зависеть от ценовой политики Intel и AMD.

Какие же выводы можно сделать из всего вышесказанного? Несмотря на многочисленные нововведения, процессор AMD Krypton-7 ненамного обгоняет в производительности Intel Pentium III (кроме наукоемких приложений, требующих интенсивных вычислений с плавающей запятой), и сильно уступает Pentium III Coppermine из-за наличия у последнего интегрированного кэша второго уровня, работающего на частоте ядра. Исключение составляют лишь многопроцессорные машины, и вполне вероятно, что Krypton-7 в какой-то степени потеснит Intel в этой области рынка. С другой стороны, сам Pentium III (исключая Coppermine) практически ничем не отличается от своего предшественника Pentium II, поэтому нет никакого смысла менять Pentium II ни на Pentium III, ни на Krypton-7 той же тактовой частоты. А вот переход с Krypton-б на Krypton-7 - пожалуй, вполне оправдан.