УДК 004.4'416:004.4'422
.1. II. Отращенко, З.Д. Акимов, Н.Н. Ефанов
Московский физико-технический институт (национальный исследовательский университет)
Разработка средства оптимизации встраиваемого ПО на базе автонастройки перестановкой оптимизационных проходов современного компилятора GCC
Современные компиляторы реализуют значительное количество оптимизационных проходов, и существенно повлиять на характеристики полученного в результате компиляции бинарного файла может последовательность, в которой они применяются. Однако любое ПО, использующее GCC как систему компиляции, не может настраивать последовательность оптимизаций ввиду отсутствия поддержки такой возможности со стороны компилятора. В данной работе рассматривается разработка способа и имплементация программного комплекса на базе GCC, позволяющего автоматически настраивать последовательности применения оптимизационных проходов компилятора при изначально заданной целевой функции. Комплекс включает в себя программы для взаимодействия непосредственно с компонентами компилятора и его оптимизационными проходами, а также ПО для интеграции с уже существующими библиотеками машинного обучения. С использованием разработанной инфраструктуры авторами реализовано два подхода для автонастройки компилятора: на основе генетического алгоритма и на основе обучения с подкреплением. Для тестирования подходов был сформирован набор открытых бенчмарков, состоящий из утилит с открытым исходным кодом, программ моделирования и уже существующих открытых бенчмарков. В ходе экспериментального сравнения подходов был получен и проанализирован выигрыш в размере бинарных файлов набора открытых бенчмарков без увеличения времени исполнения.
Ключевые слова: оптимизирующий компилятор, генетический алгоритм, машинное обучение, GCC, обучение с подкреплением, характеризация функций, автонастройка компилятора
A. I. Otrashchenko, Z.D. Akimov, N.N. Efanov Moscow institute of physics and technology (national research university)
Development of optimization framework for embedded software based on automatic tuning of modern GCC via optimisation phases reordering
Nowadays compilers have large amounts of optimizations, and the order in which these optimizations are applied can significantly impact the resulting binary. However, any-software that uses GCC as a toolchain could not choose the optimization order, because of lack of such support in the compiler. In this paper, we propose an implementation of software infrastructure, based on GCC toolchain, which allows phase-ordering in GCC with regard to given objective function. It includes infrastructure to interact with GCC and its optimization passes, and it includes integration of this infrastructure into existing machine learning packages. Using the implemented method, we explored two approaches for compiler auto-tuning by phase-ordering: genetic algorithm and reinforcement learning. For testing those approaches a benchmark set was created, which consists of utility programs, programs for modeling and existing open benchmarks. In carried out experiments, where the objective function was chosen to be size reduction without loss in runtime, the results were acquired, analyzed and compared between the approaches.
@ А. И. Отращенко, 3. Д. Акимов, H. Н. Ефанов, 2024
(с) Федеральное государственное автономное образовательное учреждение высшего образования
«Московский физико-технический институт (национальный исследовательский университет)», 2024
Key words: optimizing compiler, genetic algorithm, machine learning, GCC reinforcement learning, function characterization, compiler auto-tuning
1. Введение
Оптимизация нефункциональных характеристик программного обеспечения является актуальной проблемой программной инженерии ввиду возрастания требований к эффективности и производительности программно-аппаратных систем. В разработке ПО для встраиваемых систем наиболее актуальной является оптимизация с целями снижения размера бинарного кода, энергопотребления и времени выполнения на ключевых сценариях использования для разрабатываемого приложения. Современные оптимизирующие компиляторы [1,2] позволяют частично улучшать перечисленные характеристики посредством применения последовательностей оптимизационных проходов, упорядоченных в так называемые уровни оптимизаций, как правило, в фиксированном порядке. Тем не менее показано, что изменение порядка применения в совокупности с подключением-отключением отдельных проходов либо их последовательностей позволяет существенно улучшать показатели оптимизации для отдельных приложений и сценариев их использования, по сравнению с базовыми уровнями оптимизации [2]. В силу того что в современных компиляторах реализованы сотни различных оптимизационных проходов, поиск вышеупомянутых оптимальных наборов и последовательностей является задачей с огромным пространством поиска [2-4], что приводит к неэффективности переборных решений, и стимулирует к развитию более эффективных методов поиска, формирующих отдельную область компьютерного исследования, именуемую в настоящее время автонастройкой («автотюнингом») компилятора [2-6], преимущественно сфокусированного на ускорении поиска решений и разработку методов трансфера знаний между экспериментами [2,5]. Наиболее распространённым на данный момент открытым компиляторным решением для встраиваемых систем является компилятор ОС С [2,7-9]. Основным ограничением для построения системы автонастройки ОС С является отсутствие поддержки перестановки проходов: их порядок строго фиксирован в исходном коде менеджера проходов и не может быть изменен без перекомпиляции компилятора. Работа посвящена разработке и апробации способа автонастройки компилятора перестановкой оптимизационных проходов на основе системы принятия решений, использующей данные профилирования, статические и потоковые признаки компилируемой программы, а также разработке программного комплекса, осуществляющего автонастройку ААгсЬ64 тулчейна на базе ССС 7.3-7.5, состоящего из плагина для компилятора и системы принятия решений, управляющей данным плагином, а также экспериментам по автонастройке на базе разработанного решения с целью уменьшения размера бинарных файлов при условии неухудшения производительности в тестовых сценариях на предварительно сконструированном наборе открытых бенчмарков [10].
2. Состояние предметной области
Современное состояние предметной области характеризуется следующим: основной платформой для построения решений по автонастройке является инфраструктура 1ЛЛА1 [1], что продиктовано, в первую очередь, её гибкостью, большим количеством открытого ПО для работы с ее промежуточным представлением I. IЛ .\ I Щ и большим количеством различных решений по его характеризации [2,11-13]. ЬЬУМ-базированные решения ориентированы, в первую очередь, на оптимизацию по одному показателю: либо это улучшение производительности, либо снижение энергопотребления, либо снижение размера бинарных файлов, что чаще исследуется ввиду возможности провести поиск решения без запуска целевого приложения. Решения, ориентированные на оптимизацию по нескольким параметрам, встречаются редко и, как правило, верифицируются довольно грубо. К примеру,
в ряде решений для оптимизации по размеру файлов и по производительности оценка времени выполнения происходит на основе модели производительности либо на симуляции на относительно ограниченном по детализации микроархитектурном симуляторе. Решения, основанные на GCC относительно современных версий, основаны исключительно на включении/выключении флагов оптимизации [6], что обусловлено отсутствием поддержи перестановок оптимизирующих проходов GCC-инфраструктурой. Разработанные ранее решения, поддерживающие перестановку, несовместимы с современными версиями GCC. К примеру, разработанный и апробированный в 2009 году GCC ICI Patch, на котором основан подход MilePost GCC [4], совместим с GCC версии 4.3. С тех пор компилятор был переписан на С++ и претерпел значительное количество серьёзных изменений, в особенности связанных с дизайном и управлением оптимизационными проходами, поэтому использовать данный патч даже для версии 7.3 не представляется возможным. В силу вышесказанного, поставленная задача является актуальной в настоящее время.
3. Постановка задач
Ввиду отсутствия в настоящее время актуальных GCC-базируемых средств по автонастройке перестановкой оптимизационных проходов, авторы ставят и решают в данной работе следующие задачи:
1) разработать способ автонастройки с целью оптимизации компилируемой программы по набору характеристик, одна из которых является целевой, а остальные задают ограничения на применяемые трансформации, и реализующий его программный комплекс автоматизированной перестановки оптимизационных проходов AArch64 тулчей-на на базе GCC 7.3-7.5, состоящий из плагина, переставляющего проходы посредством управления менеджером проходов компилятора, а также системы принятия решений, разрешающей зависимости между проходами и управляющей данным плагином. Описание разработанного способа и программного комплекса дано в разд. 5.
2) на разработанном комплексе провести серии экспериментов по автонастройке компилятора с целью уменьшения размера бинарных файлов при условии неухудшения производительности: в тестовых сценариях на предварительно сконструированном наборе открытых бенчмарков провести сравнение результатов сжатия бинарных файлов по отношению к уровню оптимизации —02 для решений, основанных на поиске генетическим алгоритмом и обучением с подкреплением. Описание экспериментов и результатов приведено в разд. 6.
Более строгая формулировка задач оптимизирующей компиляции, поставленных в 2), имеет вид задачи поиска наилучшей последовательности оптимизирующих проходов, доставляющей минимум функции размера соответствующих программных единиц с ограничениями на показатели производительности оптимизируемой программы р
• для гранулярности уровня целой программы:
size(C (s,p))
^ min,
Art(C (s,p),T,02)<e
s £ S(02) - перестановка оптимизационных проходов на последовательности 02 из множества допустимых перестановок S(02), С(s,p) - результат компиляции программы р в бинарный файл с применением последовательности проходов, применяемых в порядке, заданном s, size(C(s,p)) - функция размера секции .TEXT полученного
л (rt(C (s,p),T) - rt(C (02,р),Т))
бинарного файла, Art (С (s,p),l, 02) =-ттттт^---полученные
rt(C (02,р),Т)
профилированием осреднённые измерения времени работы р на наборе тестовых сценариев Т при условии запуска на целевой платформе, е - погрешность измерений rt\
для гранулярности уровня функций:
(<01 £
i=1
size(C(Si, fi))
mm,
Art(C(s,p),T,02)<e
Si E S(02) - перестановка оптимизационных проходов на последовательности 02 компилятора GCC из множества допустимых перестановок S(02), порядок в которых отличен от 02 только для множества внутрипроцедурных проходов, применяемых к функции fi E F (е), да я F (е) - множества оптимизируемых функций в ходе компиляции, size(C(si, fi)) - размер результата компиляции fi в секции .TEXT, измеренный системной утилитой по символическому имени, экспортированному в бинарный файл, a Art(C(s,p),T,02) - осреднённые измерения времени работы, полученные профилированием. Зависимость F от е обусловлена сложностью профилирования функций, отрабатывающих за время порядка точности измерений профилировщика.
4. Предлагаемое решение
Рис. 1. Конвейер взаимодействия с GCC
Для решения поставленных задач были разработаны способы управления процессом частичной компиляции и применения перестановок проходов, характеризации компилируемой программы, а также программный инструмент РНО, осуществляющий управление процессом компиляции оптимизируемой программы в конвейерном стиле (рис. 1). Инструмент включает в себя компоненты проверки зависимостей, генерации и управления применением последовательностей проходов, объединённые в общую инфраструктуру с GCC, плагином перестановок GCC РНО Plugin, модулем характеризации программ, Unix-утилитами профилировки и чтения бинарных файлов, а также модулями, реализующими конкретный алгоритм системы принятия решений.
4.1. Перестановка оптимизационных проходов в GCC
В GCC существенную часть процесса компиляции, помимо создания абстрактного синтаксического дерева программы и процесса кодогенерации, занимает оптимизация программы (рис. 2). Так как оптимизация программ на базе синтаксического дерева и тем более на базе сгенерированного ассемблерного кода затруднительна, в компиляторе поддерживаются промежуточные представления. Такими представлениями в GCC являются GENERIC [7], GIMPLE [8], и RTL [9]. Основная роль первого - создание представления программы, транслируемого из абстрактного синтаксического дерева, не зависящего ни от исходного языка программирования, ни от целевой архитектуры. Большинство оптимизационных и анализирующих проходов происходят на представлениях GIMPLE и RTL. Оба представления могут быть приведены в SSA-форму [14].
GCC, в отличие от LLVM-утилиты opt, не предоставляет интерфейса командной строки для управления порядком применяемых проходов. Использование флагов при вызове gcc позволяет только включать или выключать некоторые проходы, но не переставлять
их. Для взаимодействия с деревом проходов был реализован плагин, использующий GCC Plugin API и публичные методы внутренних классов компилятора. Плагин представляет собой разделяемую библиотеку (*.so), загружаемую в процессе работы компилятора. Этот подход не требует изменения исходных кодов компилятора и позволяет интегрировать наше решение с существующими процессами разработки.
Рис. 2. Структура процесса компиляции в GCC
Плагин позволяет получать информацию о проходах, добавлять и удалять их, а также вычислять характеризационное векторное представление функции, компилируемой в данный момент. Плагин реализует два интерфейса взаимодействия с деревом проходов: посредством текстовых файлов, содержащих список проходов для замены и вставки, и «динамический», использующий Unix сокеты, с помощью которых можно получать информацию о компилируемой в данный момент функции и изменять применяемые к ней проходы. Первый режим изменяет дерево проходов для всего компилируемого модуля и используется в генетическом алгоритме. «Динамический» режим работает отдельно с каждой функцией и используется для обучения с подкреплением. Внутренняя структура компилятора и проходов не позволяет совершать их свободные перестановки и не гарантирует корректной работы при перестановке проходов. В GCC существует механизм «свойств» проходов, описывающих свойства внутреннего представления программы, требуемые проходам, которые компилятор может создавать и уничтожать в процессе их применения. В соответствии с этими «свойствами» и предназначением проходов из общего дерева были выделены три группы проходов, выполняющих оптимизационные, а не служебные функции. Группы содержат соответственно межпроцедурные оптимизации, внутрипроцедурные оптимизации на представлении GIMPLE, и оптимизации, работающие на представлении RTL. На практике исходных «свойств» оказалось недостаточно, чтобы гарантировать успешность и корректность компиляции, поэтому в результате экспериментов были сформированы дополнительные «свойства» для проходов, соблюдение которых необходимо для корректной компиляции. Выполнение этих «свойств» контролирует модуль shuffler. Данный модуль предоставляет API, позволяющее получить список оптимизационных проходов из данной группы, которые можно применять при данных значениях «свойств»; вычислить «свойства» по данной истории примененных проходов и выяснить корректность с точки зрения «свойств» данной последовательности проходов из данной группы. Данный модуль также дает возможность генерировать корректные с точки зрения текущих «свойств» последовательности проходов.
Помимо добавления, удаления и изменения последовательности проходов, плагин реализует более тонкое управление внутренними параметрами компилятора, влияющими на результаты применения проходов. При анализе флагов — 02 и —Os было обнаружено, что при выборе флага —Os набор исполняемых проходов не меняется, однако выставляются внутренние параметры, приводящие к оптимизациям, более направленным на уменьшение размера, чем на уменьшение времени исполнения. Включая и выключая эти флаги в процессе компиляции, можно отдельно контролировать поведение каждого прохода. Экспериментально получено, что за значительное ухудшение производительности при применении опции —Os отвечает измененная стратегия встраивания функций, тогда как внут-
рипроцедурные оптимизации часто уменьшают размер, не влияя на производительность. В связи с этим для внутрипроцедурных оптимизацией плагин в «динамическом» режиме может выставлять внутренние флаги компилятора в состояние, соответствующее оптимизации размера.
4.2. Поиск дополнительных «свойств»
Ввиду отсутствия нативной поддержки возможности перестановки оптимизационных проходов компилятора GCC некоторые из них написаны, неявно предполагая наличие или отсутствие некоего прохода до или после них. Как следствие, не все последовательности проходов допустимы при компиляции, даже при отсутствии явного запрета со стороны оригинальных «свойств». Таким образом, необходимо было найти способ обнаружить такого рода неявные зависимости для предотвращения возникновения ошибок в процессе компиляции. Ввиду большого размера кодовой базы GCC (так, оптимизационных проходов было выделено порядка сотни, имплементация каждого из которых занимает несколько тысяч строк кода) явное выделение таких зависимостей из исходного кода не представляется возможным, из-за чего потребовалось найти другой способ. Было принято следующее решение: был реализован скрипт, который с помощью модуля shuffler получает последовательности проходов, на данном этапе поиска дополнительных «свойств» считающиеся корректными. Далее, компилируется один из бенчмарков из предварительно собранного авторами набора multibenchesflO] (см. разд. 7.1) с использованием данных последовательностей, помимо этого, бенчмарк также компилируется со стандартным флагом — 02. Проверяется, во-первых, корректное завершение компиляции программы со сгенерированными последовательностями, а во-вторых, корректная работа полученного бинарного файла в сравнении с полученным при компиляции с — 02. При невыполнении одного из условий данная последовательность сохранялась и более детально изучалась на нахождение некорректной подпоследовательности проходов. Таким образом, были проработаны все бенчмарки из multibenches, с количеством сгенерированных тестовых последовательностей, превышающим несколько десятков тысяч. Такой подход не дает гарантий на отсутствие для данной программы последовательности проходов, приводящей к ошибке, однако при непосредственном поиске дополнительных «свойств» было замечено, что последние проверенные таким образом бенчмарки уже не дали никаких новых «свойств», то есть ни разу не были скомпилированы некорректно при использовании сгенерированных последовательностей. Таким образом, можно говорить о малой вероятности ошибок при перестановке проходов для других программ.
4.3. Интеграция решения в существующее ПО
Для интеграции разработанного решения с существующими библиотеками обучения с подкреплением и генетических алгоритмов были реализованы два дополнительных окружения (environment) для библиотеки Compiler Gym [5] [6]. Первое окружение, «gcc-рг» [15], использует файловый режим взаимодействия с плагином и предоставляет размер секции .TEXT исполняемого файла, время выполнения и историю примененных проходов в качестве наблюдения (observation). Награда за действие (action) соответствует формуле, используемой в генетическом алгоритме [16], и учитывает исходные размер и время выполнения. Автоматически создаваемые CompilerGvm временные папки позволяют параллельно выполняться нескольким окружениям, что уменьшает время сходимости генетического алгоритма. Второе окружение, «gcc-multienv» [17], не взаимодействует напрямую с плагином. Управление процессом компиляции и связь между окружением и плагином обеспечивает независимый модуль Benchmark Kernel. Архитектура решения приведена на рис. 3.
Для совершения одного действия и вычисления соответствующей ему награды в процессе обучения с подкреплением необходимо скомпилировать бенчмарк, передав в плагин выбранные для функций проходы, считать из полученного бинарного файла размеры инте-
ресующих символов и замерить, с разделением по функциям, время выполнения бенчмарка на тестовых сценариях. В этой последовательности шагов значительную часть времени занимает процесс компиляции и исполнения бенчмарка, так как для достаточной эффективности профилирования тестовые сценарии не должны выполняться слишком быстро и должны максимально покрывать ожидаемые сценарии использования программы в том случае, если бенчмарк создан на основе реальной утилиты. Однако один бенчмарк может содержать несколько сотен функций, каждой из которой соответствует одно окружение. Таким образом, выделение логики взаимодействия с компилятором в независимый модуль и распределение результатов его работы по нескольким окружениям позволяет добиться высокой степени распараллеливания, существенно уменьшая время и ресурсы, необходимые для обучения модели. Kernel выполняется в отдельной временной папке, содержащей исходные коды бенчмарка и файл benchmark_info.txt, хранящий информацию о бенчмарке, и использует «динамический» режим плагина при компиляции. При инициализации он создает Unix datagram-сокет в абстрактном пространстве имен, к которому подключаются новые окружения и отправляют в него последовательности проходов для выбранной функции. Kernel собирает последовательности и компилирует бенчмарк с полученными последовательностями. В процессе компиляции Kernel получает от плагина новые эмбеддинги функций, построенные методом из разд. 5.5.1. Размеры символов в бинарном файле измеряются с помощью утилиты nm. После этого процесс компиляции повторяется с дополнительным флагом gcc «-pg», включающим инструментирование программы для профилирования. Скомпилированная таким образом программа запускается на тестовых сценариях, и результаты профилирования считываются утилитой gprof*. Собранные эмбеддинги, информация о размере и времени выполнения функций отправляются в сокет соответствующего ей окружения. В случае, если Kernel не получает новых последовательностей в течение пяти минут, он закрывает сокет, удаляет свою временную папку и прекращает работу.
2.
3.
Rollout worker
Remote worker 1. Создает signle env workers Выбирает шаги 4— Возвращает Награды и Наблюдения обратно
local
worker-y
Rollout worker
Создает remote worker-ов Обновляет веса модели
Local worker
Environment:
Выбирает произвольно функцию на которой будет обучаться из датасета Подключается к существующему benchmark kernel для данного бенчмарка или создает таковой,если его не было
Получает размер функции при чистом -02 и информацию о времени исполнения, если она доступна
Имеет метод apply_action(), которым пользуется агент, чтобы выбрать проходы для применения, в котором benchmark kernel отправляет проходы и получает характеризацию функции после проходов, а также ее размер и информацию о времени исполнения, из которых вычисляет Наблюдения и Награды. Награда и Наблюдения отправляются агенту
Benchmark kernel:
Получает от каждого из environment очередные наборы проходов для соответствующих функций и отправляет их плагину
Получает от плагина характеризации функций
Benchmark kernel
Plugin:
1. Отправляет имя функции е benchmark kernel, чтобы получить
последовательность проходов
2. Применяет полученные проходы
plugin
GCC
Вычисляет размеры функций и информацию о времени исполнения, если может
Отправляет всю полученную информацию о функциях после применений проходов обратно в етлгоптеп1-ы
3. Отправляет характеризацию функции после применения проходов е benchmark kernel
Рис. 3. Архитектура окружения gcc-multienv
4.4. Поиск последовательностей: генетический алгоритм
В качестве первого подхода для автонастройки компилятора был выбран генетический алгоритм [16]. Для его имплементации использовалась библиотека РуСас! [18] и вышеупомянутое окружение gcc-pr [15] на базе СотрПегСут. В реализованном генетическом алгоритме хромосома состоит из трех наборов оптимизационных проходов, выделяемых плагином из общего дерева. Для каждого из наборов в хромосоме производится упорядоченное скрещивание по алгоритму 0X1 [19], после чего хромосома проверяется на удовлетворение «свойств»: как оригинальных, так и дополнительных. Мутация заменяет проход на пустой,
или если мутирует уже пустой проход, то заменяет его обратно на какой-то из настоящих. Вероятность замены настоящего прохода на пустой и вероятность обратной замены в сумме дают константу, и каждая из этих вероятностей изменяется с номером поколения линейно. Эта эвристика обеспечивает сужение пространства поиска на первых итерациях, а после некоторого их количества, когда алгоритм уже мог найти локальный максимум, обратно расширить пространство поиска. После каждой мутации хромосома также проверяется на корректность. Целевая функция имеет вид
где использованы обозначения из разд. 3. Критерием остановки поиска является постоянство значения целевой функции на протяжении 50 поколений. Результаты работы генетического алгоритма представлены в сводной таблице в разд. 6.3.
4.5. Поиск последовательностей: обучение с подкреплением
Для обучения с подкреплением [20] используется библиотека Ray RLLib [21] и окружение gcc-multienv. В качестве пространства действий был выбран набор из интра-процедурных проходов машинно-независимого промежуточного представления GCC GIMPLE. Такой выбор был сделан вследствие большого пространства оптимизаций, доступных на данном представлении, независимости от целевой архитектуры, а также большое количество информации об компилируемой единице, в отличие от остальных промежуточных представлений в GCC. Пространством наблюдения агента является пространство эмбеддингов, получаемых гибридным методом характеризации функций промежуточного кода, разработанного авторами.
Характеризация функций
Для обучения с подкреплением был разработан способ характеризации функций с использованием статически извлекаемой информации, предоставляемой в GIMPLE-представлении компилятора GCC. В отличие от ранее упомянутого LLVM IR, решений для характеризации по промежуточным представлениям современного GCC в открытом доступе не представлено, в силу чего потребовалось разработать способ и инструмент статической характеризации, позволяющий учитывать и статические метрики кода, и потоковую информацию, путём построения смешанного эмбеддинга. Предложенный эмбеддинг состоит из трех частей: диапазона компонент хранения статической информации о промежуточном коде, информации о потоке управления и информации о потоке данных.
Статическая информация:
Данная часть эмбеддинга реализована на базе идеи подхода Autophase [22]. Эмбеддинг, полученный на основе статической информации о коде, содержит 47 компонент (П.1).
Информация о потоке управления:
Используя API, предоставляемый GCC GIMPLE для плагинов, создавался направленный граф, где вершина - базовый блок, а ребро от базового блока А к базовому блоку В добавлялось, если контроль управления мог быть передан непосредственно от блока А к блоку В. Далее, данный граф представлялся в виде матрицы смежности и использовался алгоритм получения эмбеддинга из матрицы, по аналогии со способом получения эмбеддингов из графа потока информации, реализованного во Flow2Vec [23]: вычислялась матрица достижимости М по следующей формуле:
Art(C(s,p),T,02) > 0, Art(C(s,p),T,02) < 0,
Asize(C(s,p),02) > 0, Asize(C(s,p),02) < 0,
H
m = y, ßi-lAi,
где @ и Н - гиперпараметры, которые были выбраны равными 0.8 и 3 соответственно. Матрица М называется матрицей достижимости из-за следз^югцего свойства: она имеет ненулевой элемент в позиции 1] тогда и только тогда, когда сз^гцествз^ет путь от базового блока г до базового блока длиной меньшей или равной Н. Далее матрица достижимости раскладывается в матрицы и,Б,У с помощью сингулярного разложения [24]. Затем формируются матрицы Д^с и соответственно как К {К - гиперпараметр, который был выбран равным 25) лево- и правосингулярных векторов матрицы М, соответствующих наибольшим сингулярным значениям, умноженным на корень из соответствующего сингулярного значения. Далее, размерность данных матриц понижается с N х К до 1 х К с помощью анализа главных компонент |25|. Так, получаемый эмбеддинг графа имеет длину 2К = 50. Полная последовательность преобразований изображена на рис. 4.
Рис. 4. Схема построения эмбеддинга из направленного графа
Информация о потоке данных
Одна из причин, по которой характеризация функций происходит на С41МРЬЕ, состоит в том, что С41МРЬЕ используот ЯЗА-прсдставлснио программы, упрощающее анализ потока данных. Граф потока данных строится следующим образом: в качестве вершин в графе выступают инструкции, ребро идет от вершины г к вершине если инструкция г определяет значение, которое использз^ет инструкция ]. При наличии ББА-формы процедура создания графа запрещается. Однако в итоговый граф включается информация не только о потоке данных БЭЛ-значений, также используотся и анализ псевдонимов |2б|. Так, в С41МРЬЕ-представлении могут быть переменные, которые из-за семантики программы не могут существовать исключительно в виде БЭЛ-значений: под них должна быть выделена память, которая может быть использована и изменена из разных мест программы, например, по указателю. Из-за этого в инструкциях могут участвовать не только БЭЛ-значения, но и такие переменные напрямую, так как их значение могло измениться без явного обращения к самой переменной. Присваивания и вызовы, в которых они участвуют, анализируются с помощью предоставляемого в С4СС анализа алиасов для нахождения инструкции, где происходит определение значения данной переменной ранее по потоку исполнения. Если в функцию переходит по указателю такая переменная, то в зависимости от того константный данный указатель или нет, считается, что происходит использование или определение значения данной переменной соответственно. Полученный граф потока данных проходит все те же преобразования, что и построенный граф потока управления.
Процесс обучения
В качестве алгоритма был выбран реализованный в ЫЬНЬ алгоритм А2С [27]. Модели было предоставлено окружение §сс-пш1-Ые1ГУ (см. разд. 5.3) для абстракции процесса выбора последовательности оптимизационных проходов при компиляции. Длина эпизода была задана равной 50, в течение эпизода модель работает с одной выбранной функцией из выбранного бенчмарка, затем меняет бенчмарк и функцию. Награда за действие определяется формулой
в обозначениях из разд. 3, где Sk - последовательность оптимизационных проходов до применения выбранного, a Sk+i — после применения выбранного. Так как в данной работе приоритетным является уменьшение размера, а учет времени исполнения нужен во избежание ухудшения производительности, изменение времени исполнения имеет весовой коэффициент а. Действия, выбираемые моделью, проверяются модулем shuffler, и в случае некорректности данного действия назначается штрафная награда -1000, вследствие чего модель одновременно училась строить корректные последовательности. Так как корректность действий в текущем состоянии зависит не только от представления функции, но и от истории проходов, для восстановления марковости процесса в эмбеддинг функции добавляются два дополнительных компонента, описывающие оригинальные и дополнительные «свойства».
5. Постановка и результаты экспериментов
5.1. Multibenches — набор открытых бенчмарков
Multibenches - собранный авторами набор компилируемых и исполняемых открытых бенчмарков, адаптированных для обучения с подкреплением. Бенчмарки собирались из различных открытых наборов (cBench vl.l, LLVM test-suite, SPEC 2017), создавались из открытых утилит (gzip, zstd) и программно генерировались (csmith [28]). Каждый бенчмарк содержит файл, описывающий команды для его компиляции и запуска, а также список имен функций, сохраняющихся после встраивания функций и оказывающихся в итоговом исполняемом файле. Отдельно в файле выделен список функций, по результатам профилирования (инструментирование и профилирование с помощью gprof) занимающих более 0.5% общего времени исполнения на выбранных сценариях. Выделение списков функций позволяет в процессе обучения не тратить время и ресурсы на компиляцию и профилирование функций, не попадающих в исполняемый файл или занимающих пренебрежимо мало времени исполнения.
5.2. Постановка экспериментов Генетический алгоритм
Генетический алгоритм, описанный в разделе 5.4, был запущен на бенчмарках из Multibenches. Количество поколений было выбрано равным 250, по 40 особей в поколении, из каждого поколения оставалось по 5 родителей и в каждом очередном поколении 8 худших особей заменялось на новых особей, полученных в результате скрещивания родителей с лучшей целевой функцией. Начальные поколения были сгенерированы с помощью модуля shuffler, с целью гарантии их корректности.
Обучение с подкреплением
Экспериментальная модель, описанная в разделе 5.5, обучалась на бенчмарках из Multibenches на протяжении 50 000 шагов с постепенным уменьшением коэффициента обу-
чения от 0.0005 до 0.00001 и коэффициентом энтропии 0.01. В качестве целевых программ было выбрано подмножество из Multibenches. Для получения результатов применения обучения с подкреплением каждая программа сначала компилировалась с — 02, измерялся ее размер и время исполнения на эмуляторе qemu-aareh64 целевой архитектуры ARMv8, далее программа компилировалась с применением обученной модели, и также измерялись ее размер и время исполнения.
5.3. Анализ результатов
Результаты экспериментов представлены в табл. 1. Генетический алгоритм демонстрирует лучшие результаты практически для всех тестов, по сравнению с обучением с подкреплением, но порядки величин сжатия сопоставимы.
Таблица 1
Результаты экспериментов: процент уменьшения размера секции .TEXT исполняемого файла по сравнению с ключом — 02 GCC
Бенчмарк Ген. алгоритм, % RL A2C,%
susan 10.6 9.6
zstd 9.5 6.1
gzip 7.5 5.1
bzip2 8.3 6.5
stringseareh 4.7 3.4
patricia 5.8 7.6
bitcount 2 1.6
5 1 limb 11.3 8.9
siEan zstd gzip bzip2 string search patricia bitcount 544nab
■ Генетический алгоритм ■ RL
Рис. 5. Результаты оптимизации с помощью генетического алгоритма и Г1Ь
В силу отсутствия работ по исследованию задачи автонастройки перестановками оптимизационных проходов компилятора с использованием современного С4СС как системы компиляции с оптимизацией по нескольким параметрам, сравнение с современными аналогами не может быть проведено.
6. Заключение
В ходе работы авторами был разработан способ и инструмент С4СС РНО для оптимизации программ перестановками последовательностей оптимизационных проходов ОС С.
а также проработана методика применения различных алгоритмов поиска таких перестановок. В результате проведенных экспериментов удалось достичь сущсствсннох'о сжатия избранных бенчмарков без снижения производительности. Установлено, что обучение с подкреплением дает результаты, сопоставимые с результатами генетического алгоритма, что, в силу преимуществ первого в возможности трансфера знаний между экспериментами, говорит о предпочтительности его использования. Дальнейшими шагами авторы планируют интеграцию новых алгоритмов обучения и новых способов характеризации программ в разработанный инструмент, а также переформулировку задачи как задачи многокритериальной оптимизации и применение подходящих генетических алгоритмов к ее решению.
7. Приложение
Таблица П1
Учитываемые статические характеристики
0 Количество базовых блоков 24 Число безусловных ветвлений
1 Количество базовых блоков, у которых число аргументов у фи узлов > 5 25 Число унарных инструкций
2 Количество базовых блоков, у которых число аргументов у фи узлов < 5 26 Число инструкций, влияющих на память
3 Суммарное число аргументов у фи узлов 27 Число бинарных инструкций с константным операндом
4 Количество базовых блоков без фи узлов 28 Число целых констант
5 Количество базовых блоков с 1-3 фи узлами 29 Число целых констант, равных 0
6 Количество базовых блоков с больше. чем 3, фи узлами 30 Число целых констант, равных 1
7 Количество базовых блоков, начинающихся с фи узла 31 Число ASHK инструкций
8 Количество базовых блоков с одним предком 32 Число LSHR. инструкций
9 Количество базовых блоков с одним предком и одним наследником 33 Число SHL инструкций
10 Количество базовых блоков с одним предком и двумя наследниками •34 Число складывающих инструкций
11 Количество базовых блоков с одним наследником 35 Число вычитающих инструкций
12 Количество базовых блоков с двумя предками 36 Число умножающих инструкций
13 Количество базовых блоков с двумя наследниками 37 Число логических «И»
14 Количество базовых блоков с двумя предками и одним наследником 38 Число логических «ИЛИ»
15 Количество базовых блоков с двумя предками и двумя наследниками 39 Число логических «ИСКЛЮЧАЮЩЕЕ ИЛИ»
10 Количество базовых блоков с >2 предками 40 Число фи узлов
17 Количество базовых блоков с < 15 инструкций 41 Число вызовов функций
18 Количество базовых блоков, у которых [15, 500] инструкций 42 Число return инструкций
10 Количество ребер в графе передачи управления 43 Число load инструкций
20 Количество критических ребер в графе передачи управления 44 Число store инструкций
21 Число инструкций 45 Число icmp инструкций
22 Число инструкций, возвращающих int 46 Число trun с инструкций
23 Число ветвлений -
Таблица П2
Список бенчмарков, доступных в multibenches
bzip 2 Из cBench vl.l. Утилита для сжатия.
csmith Сгенерирован Csmith, операции с различными типами данных в структурах.
gzip Создан из утилиты для сжатия gzip.
reedsolomon Кодер-декодер на основе кодов Рида - Соломона.
smallpt Из cBench vl.l. Простой рендерер с глобальным освещением.
buublesort Сортировка пузырьком.
floatMM Умножение матриц с чисел с плавающей запятой.
zstd Создан из утилиты для сжатия zstd.
almabench Вычисления с плавающей запятой.
fft Быстрое преобразование Фурье.
huffman Алгоритм сжатия Хаффмана.
lpbench Улучшенный Linpack бенчмарк. Линейная алгебра.
gsm Из cBench vl.l. Кодирование-декодирование аудио.
poisson Численное решение уравнения Пуассона.
rsvnth Из cBench vl.l. Синтез речи.
spirit Парсер на языке С++ с значительным использованием шаблонов.
susan Из cBench vl.l. Сглаживание изображений, обнаружение углов и ребер.
bitcount Из cBench vl.l. Битовые операции с числами.
patricia Из cBench vl.l. Операции с сжатым префиксным деревом.
stringseareh Из cBench vl.l. Поиск по строкам.
SPEC2017 557.xz Утилита для сжатия.
SPEC2017 544.nab Молекулярное моделирование.
SPEC2017 557.x264 х264 видео кодек.
Список литературы
1. Lattner С., Adve V. LLVM: A Compilation Framework for Lifelong Program Analysis k, Transformation // Online. 2003. https://llvm.org/pubs/2003-09-30-LifelongOptimizationTR.pdf
2. Ashouri A.H., Killian W., Cavazos J., Palermo G., Silvano C. A Survey on Compiler Autotuning using Machine Learning // Online. 2018. https://arxiv.org/abs/1801.04405
3. Plotnikov D., Melnik D., Vardanyan M., Buchatskiy R., Zhuykov R., Lee J. A scalable auto-tuning framework for compiler optimization / / Online. 2009. https://ieeexplore.ieee.org/document/5161054
4. Fursin G., Miranda G., Temam O., Namolaru M., Yom-Tov E., Zaks A., Mendelson В., Barnard P., Ashton E., Courtois E., Courtois F., Bonilla E., Thomson J., Leather H., Williams C., O'Boyle M. MILEPOST GCC: machine learning based research compiler // International Journal of Parallel Programming. 2011. V. 39. P. 296-327.
5. Cummins С., Wasti В., Quo J., Сиг В., Ansel J., Gomez S., Jain S., Liu J., Teytaud O., Steiner В., Tian Y., Leather H. CompilerGvm: Robust, Performant Compiler Optimization Environments for AI Research // Online. 2021. https://arxiv.org/abs/2109.08267
6. CompilerGvm library // Online. 2023. https://compilergvm.com
7. GCC GENERIC // Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/GENERIC.html
8. GCC GIMPLE // Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
9. GCC RTL // Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/RTL.html
10. Multibenches // Online. 2023. https://github.com/mccs-group/multibenches
11. Zavodskih R. K., Efanov N. N. Performance prediction for chosen types of loops over one-dimensional arrays with embedding-driven intermediate representations analysis // Computer research and modeling. 2023. V. 15, I. 1. P. 211-224.
12. Cummins C., Fisches Z. V., Ben-Nun Т., Hoefler Т., Leather H. ProGraML: Graph-based Deep Learning for Program Optimization and Analysis // Online. 2018. https://arxiv.org/pdf/2003.10536.pdf
13. VenkataKeerthy S., Aggarwal R., Jain S., Desarkar M. S., Upadrasta R., Srikant Y.N. IR2VEC: LLVM IR Based Scalable Program Embeddings // ACM Transactions on Architecture and Code Optimization. 2020. V. 17, I. 4, N 32. P. 1-27.
14. Rastello F., Tichadou F.B. SSA-based compiler design // Online. 2022. https://pfalcon.github.io/ssabook/latest/book.pdf
15. Gcc_pr environment // Online. 2023. https://github.com/mccs-group/gcc_pr_env
16. Рутковская Д., Пилиньский M., Рутковский Л. Нейронные сети, генетические алгоритмы и нечеткие системы. Москва : горячая линия Телеком, 2006.
17. Gcc-multienv environment // Online. 2023. https://github.com/mccs-group/gcc_multienv
18. PvGAD - Python Genetic Algorithm! // Online. 2023. https: / / pvgad.readthedocs.io/en/latest /
19. Umbarkar A.J., Sheth P.D. Crossover Operators In Genetic Algorithms: A Review // International Journal of Computer Applications. 2017. V. 162, N 10. P. 34-36.
20. Sutton R.S. Barto A.G. Reinforcement Learning: An Introduction. Cambridge MIT Press, 2018
21. Liang E., Liaw R., Moritz P., Nishihara R., Fox R., Goldberg K., Gonzalez J.E., Jordan M.I., Stoica I. RLlib: Abstractions for Distributed Reinforcement Learning // Online. 2018. https://arxiv.org/pdf/1712.09381.pdf
22. Huang Q., Haj-Ali A., Moses W., Xiang J., Stoica I., Asanovic K., Wawrzynek J. AutoPhase: Juggling HLS Phase Orderings in Random Forests with Deep Reinforcement Learning // Online. 2020. https://arxiv.org/abs/2003.00671
23. Sui Y., Cheng X., Zhang G., Wang H. Flow2Vec: value-flow-based precise code embedding // Proceedings of the ACM on Programming Languages. V. 4, I. OOPSLA, N 233. P. 1-27.
24. Eckart, C.; Young, G. The approximation of one matrix by another of lower rank // Psvchometrika. 1. P. 211-218. Online. http://dx.doi.org/10.1007/BF02288367
25. Pearson K. LIII. On lines and planes of closest fit to systems of points in space // Philosophical Magazine and Journal of Science. 1901. V. 2, I. 11. P. 559-572.
26. Appel A.W. Modern Compiler Implementation in ML. Cambridge UK : Cambridge University Press, 1998.
27. Mnih V., Badia A.P., Mirza M., Graves A., Lillicrap /'./'.. Harley Т., Silver D., Kavukcuoglu K. Asynchronous Methods for Deep Reinforcement Learning // Proceedings of The 33rd International Conference on Machine Learning. 2016. V. 48. P. 1928-1937.
28. Yang X., Chen Y., Eide E., Regehr J. Finding and understanding bugs in C compilers // ACM-SIGPLAN Symposium on Programming Language Design and Implementation. 2011. V. 46, I. 6. P. 283-294.
References
1. Lattner C., Adve V. LLVM: A Compilation Framework for Lifelong Program Analysis k, Transformation. Online. 2003. https://llvm.org/pubs/2003-09-30-LifelongOptimizationTR.pdf
2. Ashouri A.M., Killian W., Cavazos J., Palermo G., Silvano C. A Survey on Compiler Autotuning using Machine Learning. Online. 2018. https://arxiv.org/abs/1801.04405
3. Plotnikov D., Melnik D., Vardanyan M., Buchatskiy R., Zhuykov R., Lee J. A scalable auto-tuning framework for compiler optimization. Online. 2009. https: //ieeexplore.ieee.org/document/5161054
4. Fursin G., Miranda C., Temam O., Namolaru M., Yom-Tov E., Zaks A., Mendelson B., Barnard P., Ashton E., Courtois E., Courtois F., Bonilla E., Thomson J., Leather H., Williams C., O'Boyle M. MILEPOST GCC: machine learning based research compiler. International Journal of Parallel Programming. 2011. V. 39. P. 296-327.
5. Cummins C., Wasti B., Guo J., Cui B., Ansel J., Gomez S., Jain S., Liu J., Teytaud O., Steiner B., Tian Y., Leather H. CompilerGvm: Robust, Performant Compiler Optimization Environments for AI Research. Online. 2021. https://arxiv.org/abs/2109.08267
6. CompilerGvm library. Online. 2023. https://compilergvm.com
7. GCC GENERIC. Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/GENERIC.html
8. GCC GIMPLE. Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
9. GCC RTL. Online. 2023. https://gcc.gnu.org/onlinedocs/gccint/RTL.html
10. Multibenches. Online. 2023. https://github.com/mccs-group/multibenches
11. Zavodskih R. K., Efanov N. N. Performance prediction for chosen types of loops over one-dimensional arrays with embedding-driven intermediate representations analysis. Computer research and modeling. 2023. V. 15, I. 1. P. 211-224.
12. Cummins C., Fisches Z. V., Ben-Nun T., Hoefler T., Leather H. ProGraML: Graph-based Deep Learning for Program Optimization and Analysis. Online. 2018. https://arxiv.org/pdf/2003.10536.pdf
13. VenkataKeerthy S., Aggarwal R., Jain S., Desarkar M. S., Upadrasta R., Srikant Y.N. IR2VEC: LLVM IR Based Scalable Program Embeddings. ACM Transactions on Architecture and Code Optimization. 2020. V. 17, I. 4, N 32. P. 1-27.
14. Rastello F., Tichadou F.B. SSA-based compiler design. Online. 2022. https://pfalcon.github.io/ssabook/latest/book.pdf
15. Gcc_pr environment. Online. 2023. https://github.com/mccs-group/gcc_pr_env
16. Rutkovskaja D., Pylinskij M., Rutkovskij L. Nejronnve seti, geneticheskie algoritmv i nechetkie sistemv [Neural networks, genetic algorithms and fuzzy systems], Moscow : Gorjachaja linija - Telekom, 2006. 452 p. (in Russian).
17. Gcc-multienv environment. Online. 2023. https://github.com/mccs-group/gcc_multienv
18. PvGAD - Python Genetic Algorithm! Online. 2023. https: / / pvgad.readthedocs.io / en/latest /
19. Umbarkar A.J., Sheth P.D. Crossover Operators In Genetic Algorithms: A Review. International Journal of Computer Applications. 2017. V. 162, N 10. P. 34-36.
20. Sutton R.S. Barto A.G. Reinforcement Learning: An Introduction. Cambridge MIT Press, 2018
21. Liang E., Liaw R., Moritz P., Nishihara R., Fox R., Goldberg K., Gonzalez J.E., Jordan M.I., Stoica I. RLlib: Abstractions for Distributed Reinforcement Learning. Online. 2018. https://arxiv.org/pdf/1712.09381.pdf
22. Huang Q., Haj-Ali A., Moses W., Xiang J., Stoica I., Asanovic K., Wawrzynek J. AutoPhase: Juggling HLS Phase Orderings in Random Forests with Deep Reinforcement Learning. Online. 2020. https://arxiv.org/abs/2003.00671
23. Sui Y., Cheng X., Zhang G., Wang H. Flow2Vec: value-flow-based precise code embedding. Proceedings of the ACM on Programming Languages. V. 4, I. OOPSLA, N 233. P. 1-27.
24. Eckart, C.; Young, G. The approximation of one matrix by another of lower rank. Psvchometrika. 1. P. 211-218. Online. http://dx.doi.org/10.1007/BF02288367
25. Pearson K. LIII. On lines and planes of closest fit to systems of points in space. Philosophical Magazine and Journal of Science. 1901. V. 2, I. 11. P. 559-572.
26. Appel A.W. Modern Compiler Implementation in ML. Cambridge UK : Cambridge University Press, 1998.
27. Mnih V., Badia A.P., Mirza M., Graves A., Lillicrap /'./'.. Harley T., Silver D., Kavukcuoglu K. Asynchronous Methods for Deep Reinforcement Learning. Proceedings of The 33rd International Conference on Machine Learning. 2016. V. 48. P. 1928-1937.
28. Yang X., Chen Y., Eide E., Regehr J. Finding and understanding bugs in C compilers. ACM-SIGPLAN Symposium on Programming Language Design and Implementation. 2011. V. 46, I. 6. P. 283-294.
Поступим в редакцию 27.12.2023