Содержание

2.4. Общая структура системы двоичной трансляции.

Интересно, как изнутри устроена система двоичной трансляции из x86 в E2K? Мне тоже. Тема сложная, но попытаюсь пояснить то, что, хотя бы, я сам понял, настолько просто, насколько смогу.

При подготовке материала для этой подглавы я полагался на документ с сайта МЦСТ. На данный момент на сайте МЦСТ поменяли дизайн и многиестраницы изменили свой адрес, но старая страница с этим документом влюбом случае доступна в web archive. В документе описана общая схемаработы динамической двоичной трансляции (x86 -> E2K), различные уровниоптимизаций, реализованных в системе и методы уменьшения накладныхрасходов на трансляцию. Там в целом всё довольно хорошо расписано, но,правда, неподготовленному читателю там будет тяжело разобраться.Попробуем более доступным языком описать то, что там написано.

Общая схема работы системы двоичной трансляции.

Скриншот 32. Общая схема работы системы двоичной трансляции.

Итак, ноги растут у Топлеса с чего всё стартует? Исполнение x86 кода начинается в интерпретаторе. Он собирает профильную информацию об x86 инструкциях, которые необходимо исполнить. Как только собрано достаточно сведений, запускается трансляция этих инструкций в аналогичные у E2K архитектуры. Транслированный код сохраняется в кэше трансляций (внизу).

Далее процитирую часть из статьи:

Во время работы оттранслированного кода ведётся статистика исполнения линейных участков x86-кода, на базе которой строится профильный граф.

Как это пояснить более понятным языком? Утрируя, можно сказать, что транслятор самообучается по ходу работы. Т.е. он сам адаптируется под транслируемый код так, чтобы транслировать его ещё быстрее. Считайте, некое подобие нейронной сети. Собирается информация об исполняемом коде, и на основе него строится профильный граф. Далее из профильного графа информация используется для ускорения трансляции.

В узле профильного графа хранятся: количество исполнений соответствующего линейного участка, статистика по переходам (счётчики дуг), информация о специфике инструкций, включенных в данный узел (наличие fp, mmx, sse операций и т.д.).

В общем, то, что я и описал выше: собирается полная информация о специфике исполняемого кода. На базе неё уже транслятор «обучается».

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

Более понятным языком: если один и тот же код у нас повторяется неоднократно, транслятор анализирует его и ускоряет его трансляцию.

Для осуществления переходов по x86-адресам между трансляциями используется таблица перекодировки адресов, которая хранит соответствие x86-адрес начала линейного участка → e2k-адрес транслированного кода.

Что здесь описано? У x86 машин и E2K машин адреса в памяти различаются. Когда в коде прописан вызов одного адреса памяти для x86, он автоматом по таблице перекодировки адресов (считайте, словарь для адресов памяти x86 -> E2K) переводится в аналогичный адрес для E2K. Короче говоря, при трансляции работа ведётся далеко не только с инструкциями, но и с памятью.

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

Здесь описано, что если по таблице перекодировки адресов (словарь для перевода адресов памяти x86 в аналогичные E2K) удаётся проводить работу, то трансляция ведётся с использованием этой самой таблицы. Если нет, используется интерпретатор. Интерпретатор, по сути, не будучи транслятором, является базовым уровнем многоуровневой системы двоичной трансляции. Он последовательно декодирует инструкции x86 и на основе извлечённой информации вызывает функцию, выполняющую над контекстом (регистры, память и т.д.) такое же преобразование, что и исходная инструкция, затем исполняется следующая инструкция.

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

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

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

Если вас заинтересовало то, как устроена система двоичной трансляции на Эльбрусе, если вы хотите в деталях разобраться в том, как именно работают все 4 этапа оптимизации при трансляции, настоятельно рекомендую вам ознакомиться с содержимым этого документа. А мы же перед проведением тестов зададимся вопросом: а как дела с ПО на Эльбрусе?