Виртуализация исполнения машинного кода процессорной архитектуры ARM в Android-x86 окружении (1187396), страница 9
Текст из файла (страница 9)
Например,инструкция перехода JLE (jump if less or equal — переход, если «меньше илиравен», ≤) проверяет условие «ZF=1 или SF ≠ OF».В целом архитектура x86 содержит большое разнообразие инструкцийперехода с условным выполнением, однако было решено ограничитьсяиспользованием узкого подмножества в целях упрощения кода.Таким образом в текущей реализации каждый блок непрерывного кодапропущенный через стадию трансляции также дополнительно дополняетсяинструкциейперехода,поведениекоторойполностьюсовпадаетсповедением целевой инструкции машинного кода ARM.
В случае, если впроцессетрансляциивстретиласьинструкция,котораянеявляетсяинструкцией ветвления, но которая требует условного исполнения — она60также оборачивается в блок нативного кода, который повторяет ееповедение. Отдельно стоит отметить, что несмотря на схожесть флагов вобеих архитектурах, различия в них заставляют отдельно поддерживать вофлагахархитектурыx86значения,которыеможнобезболезненноинтерпретировать при переходе в эмулятор.В конечном счете данная оптимизация позволила полностью отказатьсяот выхода в эмулятор и за счет этого был достигнут существенный прирост впроизводительности.8.
Оценки производительностиВ данном разделе будет подведены заключительные итоги опроизводительностипредлагаемоговиртуализационногорешения.Напомним, что изначальный подход, который основывался на реализацииэмуляции исполнения машинного кода ARM и поддержании консистентного(эквивалентного реальному) виртуального контекста процессора не позволилдобиться необходимой производительности в связи с чем было приняторешение применить один из видов бинарной трансляции машинного кодаARM в процессорные инструкции IA-32.Рассмотрим отдельно подход, с помощью которого производиласьоценка производительности бинарной трансляции. В целях адекватногоотслеживания изменения быстродействия предлагаемого решения быливведены две метрики: медианное количество машинных инструкций x86 наодну инструкцию ARM и отношение скорости выполнения синтетическихтестов в нативном случае на процессоре с архитектурой ARMv7 к скоростивыполнения его с помощью бинарной трансляции.
Заметим, что вторая61метрика бралась с нормировкой на тактовую частоту процессора, на которомвыполнялись тесты.Вслучае первой метрики окончательное медианное значениеколичества x86 инструкций на одну ARM инструкцию было снижено до 4-5.Заметим, что это значение варьируется в зависимости от содержаниясинтетического теста и имеет смысл рассматривать именно диапазонзначений, за которые никогда не выходит данное значение.Полученное значение с одной стороны говорит о том, что в рамкахтекущего подхода удалось реализовать достаточно эффективный алгоритмпреобразования машинного кода, который позволил минимизироватьколичество генерируемого машинного кода, что снижает как затраты натрансляцию кода, так и оптимизирует использование кэша непосредственно впроцессе исполнения транслируемого кода.
К сожалению, как уже былосказано выше, не всегда удаётся напрямую провести преобразование междуопкодами разнородных машинных архитектур, и становится необходимымиспользовать дополнительную логику в генерируемом коде для того, чтобыполностью реализовать логику поведения целевого опкода включая всеграничные случаи. Инструкции, которые требуют подобного поведения, ксчастью,встречаютсянеслишкомчасто:этовпервуюочередьзагрузка/выгрузка серии регистров по маске в/из памяти, работа со стеком,длинное умножение, а также операции битового сдвига регистров операндовна переменную величину.
Отметим также, что большинство ARMинструкций позволяет выполнять несколько арифметических действий надоперандами, что невозможно в случае архитектуры IA-32.Еще одним источником “лишних” генерируемых инструкций являетсянеобходимость перераспределения ARM регистров по нативным x8662регистрам при трансляции. И из-за недостатка последних зачастую вдлинных блоках кода, а также при переходе между блоками приходитсядобавлятьдополнительныеинструкцииобменарегистрами,чтосемантически не несет полезной нагрузки, но необходимо для достиженияконсистентностиотображениярегистров,атакжедлякорректногофункционирования оттранслированного кода. Количество таких инструкцийбыло уменьшено за счет использования регистрового аллокатора исвязывания блоков (это позволило избавиться от полной загрузки/выгрузкирегистров на входе и выходе из блоков).Однако куда более интересной с практической точки зрения являетсявторая метрика, которая описывает реальную производительность текущейреализации.Отметим,чтовсезамерыпроизводительностибылинормированы на тактовую частоту процессора, на котором производилисьзамеры, чтобы нивелировать воздействие различного быстродействия железа.Также намеренно в качестве тестовых устройств использовались процессорыпохожих классов с похожими объемами кэша различных уровней.В качестве синтетических тестов производительности использовалисьдва вида тестовых программ: хеширующая большой случайный объемданных, и программа, содержащая большое количество инструкцийветвления.
Первый тест по своей сути позволяет проанализироватьбыстродействие и эффективность бинарной трансляции на длинныхнепрерывных участках кода, но с простой логикой с точки зрения процессора(то есть с минимальным количеством ветвлений). Второй же напротив,является стресс-тестом модуля CFA, а также модуля связывания блоков,показывающий, насколько эффективно транслируется и выполняется код,состоящий из большого количества небольших участков непрерывного кода.63Таким образом измеряются потери производительности на трансляцию кодапереходов между блоками и перераспределения ARM регистров по нативнымx86 регистрам.После проведенных замеров все данные были усреднены, и избавленыот выбросов.
Также отдельно были проведены замеры под нагрузкой, как попроцессору, так и по памяти, что также дополнило картину. Анализ всехполученныхданныхпозволилсформироватьследующуюкартинупроизводительности предлагаемого решения (значения даны в доле отнативного исполнения теста на процессоре с архитектурой ARMv7 в такихже условиях):ТестхешированияТестветвленийТест хеширования(CPU stress)Тест ветвлений(memory stress)Лучшийрезультат0,820,520,750,41Худшийрезультат0,680,390,670,35В приведенной таблице результаты приведены с отброшеннымивыбросами (около 5% результатов, большинство из них связано состресс-тестами).
В итоге сделаем главные выводы из приведенных цифр:1. Была получена производительная реализация бинарной трансляции,которая обеспечивает производительность, близкую к нативной.2. Текущий подход стабильно работает как при ненагруженной системе,так и под нагрузкой, не показывая значительного уменьшения скоростивыполнения оттранслированного кода.3. Наиболее проблематичной ситуацией является наличие в программекода с малым количеством непрерывных и протяженных блоков кода ис большим количеством ветвлений. Однако даже в этом случаепроизводительность остается на приемлемом уровне.64В качестве итога можно сказать, что полученная реализация технологиивиртуализации исполнения машинного кода ARM является достаточнопроизводительной и эффективной, что позволяет использовать ее в качествеосновной системы в Parallels ARM Emulator.9.
ЗаключениеВ заключение хотелось бы еще раз отметить, что в настоящее времятехнологии виртуализации являются бурно развивающейся областьюинформационных технологий, привлекающие внимание ведущих компаний,работающих в этой сфере. В данной работе была освещена проблематикавиртуализации архитектуры ARM на процессорах x86 в приложении кпроблеме запуска Android-приложений, содержащих нативный код.В обзорной части данной работы был проведён обзор существующихтехнологий виртуализации, которые могли быть применены в данной сфере.Также был подробно рассмотрен способ, используемый в QEMU, даноподробноеописаниеалгоритмаипринципаработыдинамическойтрансляции, используемый этой программой.