4.2 Распределение регистров в микропроцессорах
Заметную роль в быстродействии программ на компьютере играет время обращения микропроцессора к данным. А именно, процессор может обращаться к:
регистрам процессора,
кэшу,
оперативной пямяти,
прочим устройствам.
Далее, рассмотрим оптимизации программ, связанные с распределением данных в этих устройствах.
Стандартный подход Хайтина.
Первыми важными работами, заложившими основы применения метода раскраски графов в распределении регистров, были , — последующие же не добавили ничего революционного, внимание в них было сконцентрировано на ускорении работы алгоритма, уменьшении памяти, новых эвристиках по определению стоимости откачки регистров и выбору регистров для откачки; обзор этих методов можно найти в .
Распределение регистров микропроцессора обычно производится на этапе компиляции.
На вход процедуры распределения подаётся некий внутренний код, который рассчитан на виртуальную машину с неограниченным числом регистров — будем называть их виртуальными регистрами.
На выходе процедуры обращения к виртуальнам регистрам переводятся либо в обращения к реальным регистрам процессора, либо, если первого нельзя сделать по причине того, что все регистры уже заняты, — в обращения к оперативной памяти путём введения дополнительного кода. Этот код называют кодом откачки, а сам процесс — откачкой. Отметим, что при обращении к оперативной памяти так же иногда используются реальные регистры.
Для примера, количество регистров общего назначения в большей части процессоров Intel, соответствующих архитектуре:
IA-32 — 8 шт.,
Intel 64 — 16 шт.
Оперативная память же можеть хранить очень большое число «откачанных» «регистров» — ограничения на её объём рассматривать не будем.
Перед выполнением самой процедуры распределения, стоит сделать:
Оптимизацию обращений к виртуальным регистрам.
Определение того, является ли переменная в данный момент «значимой», для каждого места программы. «Значима» переменная тогда, когда далее в программе происходит чтение записанного в ней в данный момент значения.
Сам алгоритм распределения регистров состоит из следующих шагов:
Построение графа — назовём его графом несовместимостей. Вершины данного графа — регистры. Вершины смежны, если соответствующие переменные «значимы» одновременно.
«Склейка» переменных: если до копирования одной переменной в другую, 2-я ещё не «значима», а 1-я не «значима» после копирования — мы можем опустить ненужную операцию перемещения и стянуть соответствующие данным переменным узлы графа.
И, наконец, самый интересный нам этап: нахождение n-раскраски графа, где n - количество вышеупомянутых реальных переменных. Решением этой задачи раскраски и является оптимальное распределение регистров. Раскрашивать будем так:
Для вершин со степенью меньше n — назначим цвет, если можно.
Для нераскрашенных вершин — «откачиваем» переменные; удаляем эти вершины из графа. Соответствнно, у соседних им вершин степень уменьшается — и имеет смысл снова сделать шаг 1.
Практика показывает, что алгоритм сходится довольно быстро.
Раскраска графа применяется во многих известных компиляторах, например в GCC версии 4.4 появился новый распределитель регистров — англ. integrated register allocator, который применяет т.н. раскраску «Хайтина-Бриггса». Раскраска «Хайтина-Бриггса» применяется и в компиляторе от Intel для архитектуры IA-64.
Учёт параллелизма на уровне команд
Процессоры, способные одновременно и независимо выполнять несколько команд, находят всё более широкое применение; о них говорят, что те поддерживают параллелизм на уровне команд. Назовём их ILP-процессорами. Класс ILP-процессоров включает в том числе процессоры с очень длинным командным словом - VLIW. Самой известной коммерчески успешной реализацией концепции параллелизма на уровне отдельных инструкций является семейство микропроцессоров Itanium компании Intel. Также стоит отметить архитектуру E2K, разработанную российской компанией МЦСТ.
Для реального использования высокой производительности ILP-процессоров необходимы компиляторы языков высокого уровня, способные генерировать эффективный код; в том числе, важна и оптимизация распределения регистров. Введение ILP требует серьёзной переработки метода Хайтина в части построения графа несовместимости; в предложен доработанный вариант.
Распределение исполняемого кода по кэшу
Был предложен также и алгоритм для распределения часто используемых областей кода в кэше — т. н. англ. cache line coloring.
Граф несовместимости здесь такой: вершины — некие «блоки» кода, рёбра существуют тогда, когда из одного «блока» ввызывается другой. Как видно, мы концентрируемся на т. н. конфликтах первого поколения — между «блоком» и её вызывающим/вызываемым. Но стоит отметить, что задача раскраски решается не алгоритмами общего назначения, а специальным эвристическим, который, к тому же, даёт решение, которое удовлетворяет неким дополнительным условиям.
Достоинство этого метода — в том, что учитываются и размеры кэша, строки кэша, «блоков» кода, и ассоциативность кэша. Метод удачно комбинируется с другими оптимизациями и inline-функциями. Надо отметить, что он может реализовываться оптимизатором — но не оптимизатором компилятора, а оптимизатором компоновщика.
- Курсовая работа
- 1 Понятие графов
- 2 Общие понятия теории графов. Понятия раскраски графов
- 2.1 Общие понятия теории графов
- 2.2 Понятие раскраски графов
- 2.3 Матрица смежности
- 2.4 Матрица инцидентности
- 3 Методы раскраски графов
- 3.1 Теорема об оптимальной раскраске
- 3.2 Теорема о четырех красках
- 3.3 Раскраска плоских графов в соответствии с теоремой о четырех красках
- 3.4 Сведение задачи о раскраске к задаче о наименьшем покрытии
- 3.5 Алгоритм, использующий метод Магу – Вейссмана
- 3.6 Алгоритм неявного перебора
- 3.7 Алгоритм прямого неявного перебора
- 4 Практичческое применение расскраски графов
- 4.1 Составление расписаний
- 4.2 Распределение регистров в микропроцессорах
- 4.3 Распределение частот
- 4.4 Использование водяных знаков
- 4.5 Прочие применения