Э. Таненбаум - Архитектура компьютера (1127755), страница 86
Текст из файла (страница 86)
По существу, они связаны с конфликтами ресурсов. При %'АК-взаимозависимости (тт'псе А(тег Кеай — запись после чтения) одна команда пытается перезаписать регистр, который предыдущая команда е1це не закончила считывать. ЪгАЖ-взаимозависимость (Жгйе Аггег %"псе — запись после записи) похожа на Ъ'АК-взаимозависимость. Подобной взаимозависимости можно избежать, если вторая команда будет помещать результат где-либо в другом месте еще (возможно, временно). Если ни одна из трех упомянутых ситуаций не возникает и нужный функциональный блок доступен, команду можно выдать.
В этом случае команда 2 использует регистр КО, который в данный момент считывается незаконченной командой, но подобное перекрытие допустимо, поэтому команда 2 может запускаться. Сходным образом команда 3 запускается во время цикла 2. А теперь перейдем к команде 4, которая должна использовать регистр К4.
К сожалению, из таблицы мы видим, что в регистр К4 в данный момент производится запись (см. строку 3 в таблице). Здесь имеет место КАтт"-взаимозависимость, поэтому блок декодирования простаивает до тех пор, пока регистр К4 не станет доступным. Во время простоя блок декодирования прекращает получать команды из блока выборки команд.
Когда внутренние буферы блока выборки команд заполнятся, он прекращает вызывать команды из памяти. Следует упомянуть, что следующая команда, команда 5, не конфликтует нн с одной из завершенных команд. Ее можно было бы декодировать и выдать, если бы в нашей системе не требовалось, чтобы команды выдавались строго по порядку. Посмотрим, что происходит в цикле 3. Команда 2, а это команда сложения (два цикла), завершается в конце цикла 3. Но ее результат не может быть сохранен 346 Глава 4. Уровень микроархитектуры в регистре К4 (который тогда освободится для команды 4).
Почему? Из-за необходимости записи результатов в регистры в соответствии с порядком выполнения программы. Но зачем? Что плохого произойдет, если сохранить результат в регистре К4 сейчас и сделать это значение доступным? Ответ на этот вопрос очень важен. Предположим, что команды могут завершаться в произвольном порядке. Тогда в случае прерывания будет очень сложно сохранить состояние машины так, чтобы его можно было потом восстановить. В частности, нельзя будет сказать, что все команды до какого-то адреса были выполнены, а все команды после этого адреса выполнены не были, как было бы при так называемом точном прерывании, которое является желательной характеристикой центрального процессора [1471.
Сохранение результатов в произвольном порядке делает прерывания неточными, н именно поэтому в некоторых машинах требуется соблюдение жесткого порядка завершения команд. Вернемся к нашему примеру. В конце цикла 4 результаты всех трех команд могут быть сохранены, поэтому в цикле 5 может быть выдана команда 4, а также недавно декодированная команда 5. Всякий раз, когда завершается какая-нибудь команда, блок декодирования должен проверять, нет ли простаивающей команды, которую уже можно выдать. В цикле 6 команда 6 простаивает, потому что ей нужно записать результат в регистр К1, а регистр К1 занят. Выполнение команды начинается только в цикле 9. Чтобы завершить всю последовательность из 8 команд, требуется 15 циклов из-за многочисленных ситуаций взаимозависимости, хотя аппаратура способна выдавать по две команды за цикл.
По колонкам «Выдача» и «Завершение» табл. 4.11 видно, что все команды выдаются из блока декодирования по порядку и завершаются эти команды тоже по порядку. Рассмотрим альтернативный подход: выполнение с изменением последовательности. В такой системе выполнение команд может начинаться в произвольном порядке и завершаться также в произвольном порядке. В табл.
4.12 показана та же последовательность из восьми команд, только теперь разрешен произвольный порядок выдачи команд и сохранения результатов в регистрах. Первое различие встречается в цикле 3. Несмотря на то, что команда 4- простаивает, мы можем декодировать и запустить команду 5, поскольку она не создает конфликтной ситуации ни с одной из выполняющихся команд. Однако пропуск команд порождает новую проблему.
Предположим, что команда 5 использует операнд, который вычисляется пропущенной командой 4. При текущем состоянии счетчика обращений мы этого не заметим. В результате нам придется расширить счетчик обращений, чтобы следить за записями, которые совершают пропущенные команды. Это можно сделать, добавив еще одно битовое отображение, по одному биту на регистр, для контроля за записями, которые делают простаивающие команды (эти счетчики в таблице не показаны). Правило запуска команд следует расширить, с тем чтобы предотвратить запуск команды, операнд которой должен был быть записан предшествующей, но пропущенной командой. Теперь посмотрим на команды 6, 7 и 8 в табл.
4.11. Здесь мы видим, что команда 6 помегцает вычисленное значение в регистр К1 и это значение используется командой 7. 3 й с й й й й 3 й й й 3 й й ° й й Я 33 й й й й 33 й й 3 с й Си Сс 44 1 Ф Ф й ~ йс "Ф сс сс И 44 Я Ф х сэ СС И сс С'Ъ (Ч 43 Ф О' 3 Ц 4О Ф 1 с1 Ф й о й й Ф О. Ф й Ф о л с Ф Ф й о о й Ф С~ О. о Ф й Ф Ф О Ф О.
о о о Ф о О О О й О. и Ф й о Ф О сО Ф а Сх сс сс сс х Ю Ю Ю к к сс 4 4 И СС С 4С сс й сс й С'4 44 й й й х сс йы И Н 4 л сс сй Ф 348 Глава 4. Уровень микроархитектуры Мы также видим, что это значение больше не требуется, потому что команда 8 переписывает значение регистра 81. Нет никакой надобности использовать регистр 81 для хранения результата команды 6.
Еше хуже то, что далеко не лучшим является выбор регистра 81 в качестве промежуточного, хотя, с точки зрения программиста, привыкшего к идее последовательного выполнения команд без перекрытий, этот выбор является самым разумным. В табл. 4.12 мы ввели новый метод для решения этой проблемы — подмену регистров (ге81згег гепаппп8). Блок декодирования заменяет регистр 81 в командах 6 (цикл 3) и 7 (цикл 4) скрытым для программиста регистром 81.
После этого команда 6 может запускаться одновременно с командой 5. Современные процессоры содержат десятки скрытых регистров, которые используются для подмены. Такая технология часто позволяет устранить ЖАВ- и ЖАЖ-взаимозависимости. В команде 8 мы снова применяем подмену регистров. На этот раз регистр 81 заменяется регистром 82, поэтому операция сложения может начаться до того, как освободится регистр 81, а освободится он только в конце цикла 6. Если окажется, что результат в этот момент должен быть в регистре В1, содержимое регистра 82 всегда можно скопировать туда. Еще лучше то, что все будущие команды, используюшие этот результат, смогут в качестве источника задействовать регистр подмены, в котором действительно хранится нужное значение.
В любом случае выполнение команды 8 начнется раньше. В настоящих (не гипотетических) компьютерах подмена регистров происходит с многократным вложением. Существует множество скрытых регистров и таблица, в которой показывается соответствие доступных программисту и скрытых регистров. Например, чтобы найти местоположение регистра ВО, нужно обратиться к элементу О этой таблицы. На самом деле реального регистра ВО нет, а есть только связь между именем йО и одним из скрытых регистров.
Эта связь часто меняется во время выполнения программы, чтобы избежать взаимозависимостей. Обратите внимание на четвертый и пятый столбец табл. 4.12. Вы видите, что команды запускаются не по порядку и завершаются также не по порядку. Вывод весьма прост: изменив последовательность выполнения команд и подменив регистры, мы можем ускорить процесс вычислений почти в два раза. Спекулятивное исполнение В предыдушем разделе мы ввели понятие переупорядочения команд, необходимого для повышения производительности.
В действительности имелось в виду переупорядочение команд в пределах одного базового блока программы. Рассмотрим этот аспект подробнее. Компьютерные программы можно разбить на базовые блоки, каждый из которых представляет собой линейную последовательность команд с точкой входа в начале и точкой выхода в конце. Базовый блок не содержит никаких управляющих структур (например, условных операторов 11 или операторов цикла иМ1е), поэтому при трансляции на машинный язык не создается никаких ветвлений.
Базовые блоки связываются операторами управления. Повышение производительности 349 Программа в такой форме может быть представлена в виде ориентированного графа, как показано на рис. 4.30. Здесь мы вычисляем сумму кубов четных и нечетных целых чисел до какого-либо предела и помещаем результаты в переменные ечепзцв и о<Ызвв соответственно (листинг 4.6). В пределах каждого базового блока технологии, упомянутые в предыдущем подразделе, работают отлично. Рис. 4.30. Граф базового блока длл фрагмента программы, приведенного в листинге 4.6 Листинг 4.6.
Фрагмент программы ечезопнО; псовое-О; 1=0: нп11е (1<11в14) ( 1ю*1*1; 1 П П ы 2 >*21 =и 1 ечепзов=ечепзов+1; е1зе оссзов=осззов ес 1=ы1: Проблема состоит в том, что большинство базовых блоков очень короткие, что не позволяет обеспечить достаточную степень параллелизма при их выполнении.