Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
12-12-2013_11-21-32 / Посовие_1.docx
Скачиваний:
92
Добавлен:
10.05.2015
Размер:
217.48 Кб
Скачать

11. Vliw (epic) микропроцессор

Недостаток динамического подхода был преодолен в микропроцессорах, архитектура которых имеет название VLIW (Very Long Instruction Word – очень длинное командное слово). VLIW архитектура известна с начала 80-х годов, но только с развитием интегральной технологии производства нашла свое достойное воплощение.

Идея VLIW микропроцессоров базируется на том, что задача эффективного планирования параллельного выполнения нескольких команд возлагается на «разумный» компилятор. Такой компилятор вначале исследует исходную программу с целью обнаружить все команды, которые могут быть выполнены параллельно, причем так, чтобы это не приводило к возникновению конфликтов. В процессе анализа компилятор может даже частично имитировать выполнение рассматриваемой программы. На следующем этапе компилятор пытается объединить такие команды в пакеты, каждый из которых рассматривается как одна сверхдлинная команда. Объединение нескольких простых команд в одну сверхдлинную производится по следующим правилам:

- количество простых команд, объединяемых в одну команду сверхбольшой длины, равно, как правило, числу имеющихся в процессоре функциональных (исполнительных) блоков (ФБ);

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

Длина сверхдлинной команды обычно составляет от 256 до 1024 бит. Такая сверхдлинная команда содержит несколько полей (по числу образующих ее простых команд), каждое из которых описывает операцию для конкретного функционального блока. Таким образом,  каждое поле сверхдлинной команды отображается на свой функциональный блок, что позволяет получить максимальную отдачу от аппаратуры блока исполнения команд. Пример сверхдлинной команды микропроцессора Itanium показан на следующем рисунке 5.

В заголовке указывается структура и длина сверхдлинной команды, в полях Операция – какие команды и в каких функциональных блоках эти команды выполняются.

Рисунок 5. Пример сверхдлинной команды

В качестве простых команд, образующих сверхдлинную команду, обычно используются команды RISC-типа. Максимальное число полей в сверхдлинной команде равно числу вычислительных устройств и обычно колеблется в диапазоне от 3 до 20. Все вычислительные устройства имеют доступ к данным, хранящимся в едином многопортовом регистровом файле. Отсутствие сложных аппаратных механизмов, характерных для суперскалярных процессоров (предсказание переходов, внеочередное исполнение и т. д.), дает значительный выигрыш в быстродействии и возможность более эффективно использовать площадь кристалла.

Наиболее полно VLIW архитектура была реализована в российском микропроцессоре Эльбрус-3М и в микропроцессоре, который был разработан совместно кампаниями HP и Intel, и который получил название Itanium-2 (или сокращенно IA-64). Для обозначения процессоров, устройство которых использует принципы статического подхода, применяется специальный термин EPIC (Explicitly Parallel Instruction Computing) или архитектура с явно выраженной параллельностью на уровне команд.

Развитие концепции параллелизма на уровне команд определяет новый тип архитектуры микропроцессоров. Такая идеология направлена на то, чтобы упростить аппаратное обеспечение и, в то же время, извлечь как можно больше «скрытого параллелизма» на уровне команд. Архитектура EPIC упрощает два ключевых момента, реализуемых во время выполнения программ. Во-первых, принципы этой архитектуры позволяют во время исполнения отказаться от проверки зависимостей между операциями, которые компилятор уже объявил как независимые.

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

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

Процессоры EPIC представляют собой пример архитектуры, для которой программа предоставляет точную информацию о параллелизме — компилятор выявляет параллелизм в программе и сообщает аппаратному обеспечению, какие операции не зависят друг от друга. Эта информация имеет большое значение для аппаратуры, поскольку в этом случае она «знает» без дальнейших проверок какие операции можно начинать выполнять в одном и том же такте. Архитектура EPIC — это эволюция архитектуры VLIW, которая абсорбировала в себе многие концепции суперскалярной архитектуры, хотя и в форме, адаптированной к EPIC. По сути — это «идеология», определяющая, как создавать ILP-процессоры, а также набор характеристик архитектуры, которые поддерживают данную основу.

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

В отличие от программ для суперскалярных процессоров, код EPIC предлагает точный план (POE — Plan Of Execution, схема исполнения создается статически во время компиляции) того, как процессор будет выполнять программу. Код точно указывает, когда будет выполнена каждая операция, какие функциональные устройства должны работать и какие регистры будут содержать операнды. Компилятор EPIC создает такой план выполнения, имея полное представление о самом процессоре, чтобы добиться требуемой последовательности событий, которые действительно происходят во время работы программы. Компилятор передает POE (через архитектуру набора команд, которая точно описывает параллелизм) аппаратному обеспечению, которое, в свою очередь, выполняет указанный план. Этот план позволяет EPIC использовать относительно простое аппаратное обеспечение, способное добиться высокого уровня ILP. В отличие от EPIC, суперскалярная архитектура динамически строит POE на основе последовательного кода. Хотя такой подход и увеличивает сложность физической реализации, суперскалярный процессор создает план, используя преимущества тех факторов, которые могут быть определены только во время выполнения.

Одна из целей, которая ставилась при создании EPIC, состояла в том, чтобы сохранить реализованный во VLIW принцип статического создания POE, но и в то же время обогатить его возможностями, аналогичными возможностям суперскалярного процессора, позволяющими новой архитектуре лучше учитывать динамические факторы, традиционно ограничивающие параллелизм, свойственный VLIW. Чтобы добиться этих целей, «идеология» EPIC была построена на некоторых основных принципах.

Первый принцип — это создание плана выполнения во время компиляции. EPIC возлагает нагрузку по созданию POE на компилятор. Хотя, в общем, архитектура и физическая реализация могут препятствовать компилятору в выполнении этой задачи, процессоры EPIC предоставляют функции, которые помогают компилятору создавать план выполнения. Во время исполнения программы поведение процессора EPIC с точки зрения компилятора должно быть предсказуемым и управляемым. Динамическое внеочередное исполнение команд может «запутать» компилятор так, что он не будет «понимать», как его решения повлияют на реальную запись выполнения, созданную процессором, поэтому ему необходимо уметь предсказывать действия процессора, что еще больше усложняет задачу. В данной ситуации предпочтителен процессор, четко исполняющий то, что ему указывает программа. Суть же создания плана во время компиляции состоит в переупорядочивании исходного последовательного кода так, чтобы использовать все преимущества параллелизма программы и максимально эффективно использовать аппаратные ресурсы, минимизируя время выполнения. Без соответствующей поддержки архитектуры такое переупорядочивание может нарушить корректность программы. Таким образом, поскольку EPIC возлагает создание POE на компилятор, она должна обеспечивать еще и архитектурные возможности, поддерживающие интенсивное переупорядочивание кода во время компиляции.

Следующим принципом является использование компилятором вероятностных оценок. Компилятор EPIC сталкивается с серьезной проблемой при создании плана выполнения: информация определенного типа, которая существенно влияет на порядок исполнения, становится известна только лишь в момент выполнения программы. Например, компилятор не может точно знать, какая из ветвей после оператора перехода будет выполняться, когда запланированный код пройдет базовые блоки и какой из путей графа будет выбран. Кроме того, обычно невозможно создать статический план, который одновременно оптимизирует все пути в программе. Неоднозначность также возникает и в тех случаях, когда компилятор не может решить, будут ли ссылки указывать на одно и то же место в памяти. Если да, то обращение к ним должно осуществляться последовательно; если нет, то их можно запланировать в произвольном порядке. При такой неоднозначности часто наиболее вероятен некий конкретный результат. Одним из важнейших принципов EPIC в данной ситуации является возможность разрешения компилятору оперировать вероятностными оценками — он создает и оптимизирует POE для наиболее вероятных случаев.

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

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

  • режим спекулятивных (упреждающих) вычислений, которые нужны, чтобы уменьшить зависимости, связанные с условной передачей управления;

  • исполнение операций под управлением предиката позволяет избавиться во многих случаях от операций передачи управления, что ведет к увеличению параллелизма и, как следствие, к росту скорости работы микропроцессора;

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

Рассмотрим данные архитектурные черты более подробно.

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

Рассмотрим следующую последовательность кода:

if (a>b) load (ld_addr1,target1)

else load (ld_addr2,target2)

Если операция load (ld_addr1,target1) была выполнена предварительно, до завершения проверки (a>b), то операция будет спекулятивной по управлению по отношению к управляющему условию (a>b). При нормальном выполнении операция load (ld_addr1,target1) может быть выполнена, а может быть, и не выполнена. Если новая спекулятивная загрузка по управлению явится причиной исключения, то исключение будет обслуживаться, только если (a>b). Когда компилятор использует спекуляцию по управлению, он оставляет операцию проверки на своем месте. Проверка проверяет, произошло ли исключение и если произошло, то осуществляется переход к восстанавливающему (recovery) коду.

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

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

Другой ключевой особенностью EPIC-микропроцессоров является предварительная (спекулятивная) загрузка данных. Она позволяет не только загружать данные из памяти до того, как они понадобятся программе, но и генерировать исключение в тех случаях, когда загрузка прошла неудачно. Цель предварительной загрузки - разделить собственно загрузку и использование данных, что позволяет избежать простоя процессора.

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

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

Вообще говоря, спекулятивность по данным — это выполнение загрузки из памяти до сохранения, которое могло предшествовать ему, и которое может потенциально изменить эту загрузку. Рассмотрим следующую последовательность:

store(st_addr,data)

load (ld_addr,target)

use (target).

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

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

Вообще говоря, предикатность (predication) — это условное выполнение инструкций. В CISC микропроцессорах условное выполнение осуществляется с помощью инструкций переходов. В EPIC архитектуре эта функция реализуется с использованием предикатности инструкций. Предикатность удаляет переходы, используемые для получения условного выполнения в больших основных блоках, и устраняет потери, связанные с ошибочными предсказаниями переходов.

Рассмотрим инструкцию без предикатов:

r1 = r2 + r3,

если эту инструкцию предикатировать, то она примет вид

if (p5) r1 = r2 + r3

В этом примере р5 является условием (предикатом) управления, который решает — будет или не будет эта инструкция выполняться и изменять состояние. Если значение условия — истина, то инструкция обновит состояние. В противном случае инструкция эквивалентна команде NOP. Предикаты — это значения, назначенные командами сравнения.

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

if (a>b) c = c + 1

else d = d * e + f

Т.е. необходимо проверить условие a>b, и если это условие выполняется, то должен выполниться инкремент c, в противном случае должно быть выполнено

d = d * e + f

Можно избежать перехода по условию путем превращения кода в предикатный код:

pT, pF = compare(a>b)

if (pT) c = c + 1

if (pF) d = d * e + f

Если условие будет истинным, то предикат рТ будет установлен в 1, иначе — в 0. Предикат pF является обратным по отношению к рТ. Зависимость по управлению в инструкциях c = c + 1 и d = d * e + f, выраженная в переходе по условию (a>b) теперь, преобразуется в зависимость по данным рТ и pF, которые получаются в результате операции compare(a>b), а переход ликвидируется. Дополнительный выигрыш состоит в том, что компилятор может планировать инструкции с рТ и pF для параллельного выполнения.

Выше были представлены примеры использования предикатного исполнения. Общая идея использования предикатов заключается в следующем.  Когда компилятор для EPIC микропроцессора находит оператор ветвления в исходном коде, он исследует ветвление, определяя, стоит ли его "отмечать". Если такое решение принято, компилятор помечает все команды, относящиеся к одному пути ветвления, уникальным идентификатором, называемым предикатом. Например, путь, соответствующий значению условия ветвления TRUE, помечается предикатом Р1, а каждая команда пути, соответствующего значению условия ветвления FALSE - предикатом Р2. Система команд микропроцессоров EPIC определяет для каждой команды 6-битное поле для хранения этого предиката. Таким образом, одновременно могут быть использованы 64 различных предиката. После того, как команды "отмечены", компилятор определяет, какие из них могут выполняться параллельно. Кроме того, компилятор, естественно, должен учитывать зависимости в данных (две команды, одна из которых использует результат другой, не могут выполняться параллельно). Поскольку каждый путь ветвления заведомо не зависит от других, какое-то "количество параллелизма" почти всегда будет найдено.

Как уже было сказано команды микропроцессора Itanium объединяются в связки по три независимые инструкции, которые затем исполняются параллельно. Каждая связка занимает 16 байт. В архитектуре Itanium определены допустимые шаблоны связок. В связке можно использовать следующие типы команд:

M - операции с памятью / присваивание;

I - сложные целочисленные / векторные операции;

A - простые целочисленные / логические / векторные операции;

F - вещественные операции (обычные / векторные);

B - команды ветвлений.

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

логические операции;

арифметические операции;

операции сравнения;

операции сдвига;

векторные целочисленные операции;

команды передачи управления (ветвлений);

команды ветвлений для организации циклов;

вещественные операции;

векторные вещественные операции;

операции с памятью;

операции присваивания;

команды управления кэшированием.

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

Соседние файлы в папке 12-12-2013_11-21-32